mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-05 07:17:45 -04:00
sound, improve ym2612 accuracy (NB noticeably slower for low bitrates)
This commit is contained in:
parent
c3fcdf3f8d
commit
d127b3f3d5
3 changed files with 361 additions and 438 deletions
|
@ -8,7 +8,6 @@
|
|||
**
|
||||
** updated with fixes from mame 0.216 (file version 1.5.1) (kub)
|
||||
** SSG-EG readded from GenPlus (kub)
|
||||
** linear sample interpolation for chip to output rate adaption (kub)
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -909,7 +908,7 @@ typedef struct
|
|||
UINT32 eg_timer;
|
||||
UINT32 eg_timer_add;
|
||||
UINT32 pack; // 4c: stereo, lastchan, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16]
|
||||
UINT32 algo; /* 50: algo[3], was_update */
|
||||
UINT32 algo; /* 50: algo[3], was_update, unsued, upd_cnt[2], dac */
|
||||
INT32 op1_out;
|
||||
#ifdef _MIPS_ARCH_ALLEGREX
|
||||
UINT32 pad1[3+8];
|
||||
|
@ -921,10 +920,211 @@ typedef struct
|
|||
#include <limits.h>
|
||||
static int clip(int n)
|
||||
{
|
||||
unsigned b = 14, s = n < 0;
|
||||
int m = s + INT_MAX;
|
||||
if (s + (n>>(b-1))) n = m >> (8*sizeof(int)-b);
|
||||
return n;
|
||||
unsigned b = 14, s = n < 0;
|
||||
int m = s + INT_MAX;
|
||||
if (s + (n>>(b-1))) n = m >> (8*sizeof(int)-b);
|
||||
return n;
|
||||
}
|
||||
|
||||
static void update_ssg_eg_channel(chan_rend_context *ct)
|
||||
{
|
||||
FM_SLOT *SLOT;
|
||||
|
||||
SLOT = &ct->CH->SLOT[SLOT1];
|
||||
if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200)
|
||||
ct->phase1 = update_ssg_eg_phase(SLOT, ct->phase1);
|
||||
SLOT = &ct->CH->SLOT[SLOT2];
|
||||
if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200)
|
||||
ct->phase2 = update_ssg_eg_phase(SLOT, ct->phase2);
|
||||
SLOT = &ct->CH->SLOT[SLOT3];
|
||||
if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200)
|
||||
ct->phase3 = update_ssg_eg_phase(SLOT, ct->phase3);
|
||||
SLOT = &ct->CH->SLOT[SLOT4];
|
||||
if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200)
|
||||
ct->phase4 = update_ssg_eg_phase(SLOT, ct->phase4);
|
||||
}
|
||||
|
||||
static void update_eg_phase_channel(chan_rend_context *ct)
|
||||
{
|
||||
FM_SLOT *SLOT;
|
||||
|
||||
SLOT = &ct->CH->SLOT[SLOT1];
|
||||
if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt, ct->pack & 2);
|
||||
SLOT = &ct->CH->SLOT[SLOT2];
|
||||
if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt, ct->pack & 2);
|
||||
SLOT = &ct->CH->SLOT[SLOT3];
|
||||
if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt, ct->pack & 2);
|
||||
SLOT = &ct->CH->SLOT[SLOT4];
|
||||
if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt, ct->pack & 2);
|
||||
}
|
||||
|
||||
static int update_algo_channel(chan_rend_context *ct, unsigned int eg_out, unsigned int eg_out2, unsigned int eg_out4)
|
||||
{
|
||||
int m2,c1,c2=0; /* Phase Modulation input for operators 2,3,4 */
|
||||
int smp = 0;
|
||||
|
||||
switch( ct->algo&0x7 )
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
/* M1---C1---MEM---M2---C2---OUT */
|
||||
m2 = ct->mem;
|
||||
c1 = ct->op1_out>>16;
|
||||
if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */
|
||||
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);
|
||||
}
|
||||
if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */
|
||||
smp = op_calc(ct->phase4, eg_out4, c2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
/* M1------+-MEM---M2---C2---OUT */
|
||||
/* C1-+ */
|
||||
m2 = ct->mem;
|
||||
ct->mem = ct->op1_out>>16;
|
||||
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);
|
||||
}
|
||||
if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */
|
||||
smp = op_calc(ct->phase4, eg_out4, c2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
/* M1-----------------+-C2---OUT */
|
||||
/* C1---MEM---M2-+ */
|
||||
m2 = ct->mem;
|
||||
c2 = ct->op1_out>>16;
|
||||
if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */
|
||||
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);
|
||||
}
|
||||
if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */
|
||||
smp = op_calc(ct->phase4, eg_out4, c2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
/* M1---C1---MEM------+-C2---OUT */
|
||||
/* M2-+ */
|
||||
c2 = ct->mem;
|
||||
c1 = ct->op1_out>>16;
|
||||
if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */
|
||||
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);
|
||||
}
|
||||
if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */
|
||||
smp = op_calc(ct->phase4, eg_out4, c2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
/* 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 */
|
||||
c2 = op_calc(ct->phase3, eg_out, 0);
|
||||
}
|
||||
if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */
|
||||
smp = op_calc(ct->phase2, eg_out2, c1);
|
||||
}
|
||||
if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */
|
||||
smp+= op_calc(ct->phase4, eg_out4, c2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
/* +----C1----+ */
|
||||
/* M1-+-MEM---M2-+-OUT */
|
||||
/* +----C2----+ */
|
||||
if (ct->eg_timer >= (1<<EG_SH)) break;
|
||||
|
||||
m2 = ct->mem;
|
||||
ct->mem = c1 = c2 = ct->op1_out>>16;
|
||||
if( eg_out < ENV_QUIET ) { /* SLOT 3 */
|
||||
smp = op_calc(ct->phase3, eg_out, m2);
|
||||
}
|
||||
if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */
|
||||
smp+= op_calc(ct->phase2, eg_out2, c1);
|
||||
}
|
||||
if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */
|
||||
smp+= op_calc(ct->phase4, eg_out4, c2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
/* M1---C1-+ */
|
||||
/* 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 */
|
||||
smp = op_calc(ct->phase3, eg_out, 0);
|
||||
}
|
||||
if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */
|
||||
smp+= op_calc(ct->phase2, eg_out2, c1);
|
||||
}
|
||||
if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */
|
||||
smp+= op_calc(ct->phase4, eg_out4, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
/* M1-+ */
|
||||
/* C1-+-OUT */
|
||||
/* 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 */
|
||||
smp += op_calc(ct->phase3, eg_out, 0);
|
||||
}
|
||||
if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */
|
||||
smp += op_calc(ct->phase2, eg_out2, 0);
|
||||
}
|
||||
if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */
|
||||
smp += op_calc(ct->phase4, eg_out4, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return smp;
|
||||
}
|
||||
|
||||
static void chan_render_loop(chan_rend_context *ct, int *buffer, int length)
|
||||
|
@ -936,302 +1136,76 @@ static void chan_render_loop(chan_rend_context *ct, int *buffer, int length)
|
|||
{
|
||||
int smp = 0; /* produced sample */
|
||||
unsigned int eg_out, eg_out2, eg_out4;
|
||||
FM_SLOT *SLOT;
|
||||
UINT32 cnt = ct->eg_timer_add+(ct->eg_timer & ((1<<EG_SH)-1));
|
||||
|
||||
if (ct->pack & 2) while (cnt >= 1<<EG_SH) {
|
||||
cnt -= 1<<EG_SH;
|
||||
SLOT = &ct->CH->SLOT[SLOT1];
|
||||
if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200)
|
||||
ct->phase1 = update_ssg_eg_phase(SLOT, ct->phase1);
|
||||
SLOT = &ct->CH->SLOT[SLOT2];
|
||||
if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200)
|
||||
ct->phase2 = update_ssg_eg_phase(SLOT, ct->phase2);
|
||||
SLOT = &ct->CH->SLOT[SLOT3];
|
||||
if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200)
|
||||
ct->phase3 = update_ssg_eg_phase(SLOT, ct->phase3);
|
||||
SLOT = &ct->CH->SLOT[SLOT4];
|
||||
if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200)
|
||||
ct->phase4 = update_ssg_eg_phase(SLOT, ct->phase4);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ct->eg_timer += ct->eg_timer_add;
|
||||
if (ct->eg_timer < EG_TIMER_OVERFLOW) {
|
||||
SLOT = &ct->CH->SLOT[SLOT1];
|
||||
SLOT->vol_ipol = SLOT->vol_out;
|
||||
if (SLOT->state > EG_REL) recalc_volout(SLOT);
|
||||
SLOT = &ct->CH->SLOT[SLOT2];
|
||||
SLOT->vol_ipol = SLOT->vol_out;
|
||||
if (SLOT->state > EG_REL) recalc_volout(SLOT);
|
||||
SLOT = &ct->CH->SLOT[SLOT3];
|
||||
SLOT->vol_ipol = SLOT->vol_out;
|
||||
if (SLOT->state > EG_REL) recalc_volout(SLOT);
|
||||
SLOT = &ct->CH->SLOT[SLOT4];
|
||||
SLOT->vol_ipol = SLOT->vol_out;
|
||||
if (SLOT->state > EG_REL) recalc_volout(SLOT);
|
||||
}
|
||||
else while (ct->eg_timer >= EG_TIMER_OVERFLOW)
|
||||
{
|
||||
ct->eg_timer -= EG_TIMER_OVERFLOW;
|
||||
ct->eg_cnt++;
|
||||
if (ct->eg_cnt >= 4096) ct->eg_cnt = 1;
|
||||
while (ct->eg_timer >= 1<<EG_SH) {
|
||||
ct->eg_timer -= 1<<EG_SH;
|
||||
|
||||
SLOT = &ct->CH->SLOT[SLOT1];
|
||||
SLOT->vol_ipol = SLOT->vol_out;
|
||||
if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt, ct->pack & 2);
|
||||
SLOT = &ct->CH->SLOT[SLOT2];
|
||||
SLOT->vol_ipol = SLOT->vol_out;
|
||||
if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt, ct->pack & 2);
|
||||
SLOT = &ct->CH->SLOT[SLOT3];
|
||||
SLOT->vol_ipol = SLOT->vol_out;
|
||||
if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt, ct->pack & 2);
|
||||
SLOT = &ct->CH->SLOT[SLOT4];
|
||||
SLOT->vol_ipol = SLOT->vol_out;
|
||||
if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt, ct->pack & 2);
|
||||
}
|
||||
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 & 2)
|
||||
update_ssg_eg_channel(ct);
|
||||
|
||||
if (ct->algo & 0x30)
|
||||
ct->algo -= 0x10;
|
||||
if (!(ct->algo & 0x30)) {
|
||||
ct->algo |= 0x30;
|
||||
ct->eg_cnt++;
|
||||
if (ct->eg_cnt >= 4096) ct->eg_cnt = 1;
|
||||
|
||||
update_eg_phase_channel(ct);
|
||||
}
|
||||
|
||||
#if 0
|
||||
UINT32 ifrac0 = ct->eg_timer / (EG_TIMER_OVERFLOW>>EG_SH);
|
||||
UINT32 ifrac1 = (1<<EG_SH) - ifrac0;
|
||||
SLOT = &ct->CH->SLOT[SLOT1];
|
||||
ct->vol_out1 = (SLOT->vol_ipol*ifrac1 + SLOT->vol_out*ifrac0) >> EG_SH;
|
||||
SLOT = &ct->CH->SLOT[SLOT2];
|
||||
ct->vol_out2 = (SLOT->vol_ipol*ifrac1 + SLOT->vol_out*ifrac0) >> EG_SH;
|
||||
SLOT = &ct->CH->SLOT[SLOT3];
|
||||
ct->vol_out3 = (SLOT->vol_ipol*ifrac1 + SLOT->vol_out*ifrac0) >> EG_SH;
|
||||
SLOT = &ct->CH->SLOT[SLOT4];
|
||||
ct->vol_out4 = (SLOT->vol_ipol*ifrac1 + SLOT->vol_out*ifrac0) >> EG_SH;
|
||||
#elif 1
|
||||
switch (ct->eg_timer >> EG_SH)
|
||||
{
|
||||
case 0:
|
||||
ct->vol_out1 = ct->CH->SLOT[SLOT1].vol_ipol;
|
||||
ct->vol_out2 = ct->CH->SLOT[SLOT2].vol_ipol;
|
||||
ct->vol_out3 = ct->CH->SLOT[SLOT3].vol_ipol;
|
||||
ct->vol_out4 = ct->CH->SLOT[SLOT4].vol_ipol;
|
||||
break;
|
||||
case (EG_TIMER_OVERFLOW>>EG_SH)-1:
|
||||
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;
|
||||
break;
|
||||
default:
|
||||
ct->vol_out1 = (ct->CH->SLOT[SLOT1].vol_ipol +
|
||||
ct->CH->SLOT[SLOT1].vol_out) >> 1;
|
||||
ct->vol_out2 = (ct->CH->SLOT[SLOT2].vol_ipol +
|
||||
ct->CH->SLOT[SLOT2].vol_out) >> 1;
|
||||
ct->vol_out3 = (ct->CH->SLOT[SLOT3].vol_ipol +
|
||||
ct->CH->SLOT[SLOT3].vol_out) >> 1;
|
||||
ct->vol_out4 = (ct->CH->SLOT[SLOT4].vol_ipol +
|
||||
ct->CH->SLOT[SLOT4].vol_out) >> 1;
|
||||
break;
|
||||
}
|
||||
#elif 0
|
||||
if (ct->eg_timer >> (EG_SH-1) < EG_TIMER_OVERFLOW >> EG_SH) {
|
||||
ct->vol_out1 = ct->CH->SLOT[SLOT1].vol_ipol;
|
||||
ct->vol_out2 = ct->CH->SLOT[SLOT2].vol_ipol;
|
||||
ct->vol_out3 = ct->CH->SLOT[SLOT3].vol_ipol;
|
||||
ct->vol_out4 = ct->CH->SLOT[SLOT4].vol_ipol;
|
||||
} else {
|
||||
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 */
|
||||
|
||||
/* calculate channel sample */
|
||||
if (ct->eg_timer < (2<<EG_SH) || (ct->pack&0xf000)) {
|
||||
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>>16) + ((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;
|
||||
}
|
||||
#else
|
||||
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;
|
||||
#endif
|
||||
|
||||
if (ct->pack & 4) continue; /* 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( eg_out < ENV_QUIET ) /* SLOT 1 */
|
||||
{
|
||||
int out = 0;
|
||||
|
||||
if (ct->pack&0xf000) out = ((ct->op1_out>>16) + ((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;
|
||||
}
|
||||
|
||||
switch( ct->algo&0x7 )
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
/* M1---C1---MEM---M2---C2---OUT */
|
||||
int m2,c1,c2=0; /* Phase Modulation input for operators 2,3,4 */
|
||||
m2 = ct->mem;
|
||||
c1 = ct->op1_out>>16;
|
||||
if( eg_out < ENV_QUIET ) { /* SLOT 3 */
|
||||
c2 = op_calc(ct->phase3, eg_out, m2);
|
||||
}
|
||||
if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */
|
||||
ct->mem = op_calc(ct->phase2, eg_out2, c1);
|
||||
}
|
||||
else ct->mem = 0;
|
||||
if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */
|
||||
smp = op_calc(ct->phase4, eg_out4, c2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
/* M1------+-MEM---M2---C2---OUT */
|
||||
/* C1-+ */
|
||||
int m2,c2=0;
|
||||
m2 = ct->mem;
|
||||
ct->mem = ct->op1_out>>16;
|
||||
if( eg_out < ENV_QUIET ) { /* SLOT 3 */
|
||||
c2 = op_calc(ct->phase3, eg_out, m2);
|
||||
}
|
||||
if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */
|
||||
ct->mem+= op_calc(ct->phase2, eg_out2, 0);
|
||||
}
|
||||
if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */
|
||||
smp = op_calc(ct->phase4, eg_out4, c2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
/* M1-----------------+-C2---OUT */
|
||||
/* C1---MEM---M2-+ */
|
||||
int m2,c2;
|
||||
m2 = ct->mem;
|
||||
c2 = ct->op1_out>>16;
|
||||
if( eg_out < ENV_QUIET ) { /* SLOT 3 */
|
||||
c2 += op_calc(ct->phase3, eg_out, m2);
|
||||
}
|
||||
if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */
|
||||
ct->mem = op_calc(ct->phase2, eg_out2, 0);
|
||||
}
|
||||
else ct->mem = 0;
|
||||
if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */
|
||||
smp = op_calc(ct->phase4, eg_out4, c2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
/* M1---C1---MEM------+-C2---OUT */
|
||||
/* M2-+ */
|
||||
int c1,c2;
|
||||
c2 = ct->mem;
|
||||
c1 = ct->op1_out>>16;
|
||||
if( eg_out < ENV_QUIET ) { /* SLOT 3 */
|
||||
c2 += op_calc(ct->phase3, eg_out, 0);
|
||||
}
|
||||
if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */
|
||||
ct->mem = op_calc(ct->phase2, eg_out2, c1);
|
||||
}
|
||||
else ct->mem = 0;
|
||||
if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */
|
||||
smp = op_calc(ct->phase4, eg_out4, c2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
/* M1---C1-+-OUT */
|
||||
/* M2---C2-+ */
|
||||
/* MEM: not used */
|
||||
int c1,c2=0;
|
||||
c1 = ct->op1_out>>16;
|
||||
if( eg_out < ENV_QUIET ) { /* SLOT 3 */
|
||||
c2 = op_calc(ct->phase3, eg_out, 0);
|
||||
}
|
||||
if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */
|
||||
smp = op_calc(ct->phase2, eg_out2, c1);
|
||||
}
|
||||
if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */
|
||||
smp+= op_calc(ct->phase4, eg_out4, c2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
/* +----C1----+ */
|
||||
/* M1-+-MEM---M2-+-OUT */
|
||||
/* +----C2----+ */
|
||||
int m2,c1,c2;
|
||||
m2 = ct->mem;
|
||||
ct->mem = c1 = c2 = ct->op1_out>>16;
|
||||
if( eg_out < ENV_QUIET ) { /* SLOT 3 */
|
||||
smp = op_calc(ct->phase3, eg_out, m2);
|
||||
}
|
||||
if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */
|
||||
smp+= op_calc(ct->phase2, eg_out2, c1);
|
||||
}
|
||||
if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */
|
||||
smp+= op_calc(ct->phase4, eg_out4, c2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
/* M1---C1-+ */
|
||||
/* M2-+-OUT */
|
||||
/* C2-+ */
|
||||
/* MEM: not used */
|
||||
int c1;
|
||||
c1 = ct->op1_out>>16;
|
||||
if( eg_out < ENV_QUIET ) { /* SLOT 3 */
|
||||
smp = op_calc(ct->phase3, eg_out, 0);
|
||||
}
|
||||
if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */
|
||||
smp+= op_calc(ct->phase2, eg_out2, c1);
|
||||
}
|
||||
if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */
|
||||
smp+= op_calc(ct->phase4, eg_out4, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
/* M1-+ */
|
||||
/* C1-+-OUT */
|
||||
/* M2-+ */
|
||||
/* C2-+ */
|
||||
/* MEM: not used*/
|
||||
smp = ct->op1_out>>16;
|
||||
if( eg_out < ENV_QUIET ) { /* SLOT 3 */
|
||||
smp += op_calc(ct->phase3, eg_out, 0);
|
||||
}
|
||||
if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */
|
||||
smp += op_calc(ct->phase2, eg_out2, 0);
|
||||
}
|
||||
if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */
|
||||
smp += op_calc(ct->phase4, eg_out4, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* done calculating channel sample */
|
||||
|
||||
/* mix sample to output buffer */
|
||||
if (smp) {
|
||||
|
@ -1250,12 +1224,6 @@ static void chan_render_loop(chan_rend_context *ct, int *buffer, int length)
|
|||
}
|
||||
ct->algo |= 8;
|
||||
}
|
||||
|
||||
/* update phase counters AFTER output calculations */
|
||||
ct->phase1 += ct->incr1;
|
||||
ct->phase2 += ct->incr2;
|
||||
ct->phase3 += ct->incr3;
|
||||
ct->phase4 += ct->incr4;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
@ -1335,6 +1303,7 @@ static int chan_render(int *buffer, int length, int c, UINT32 flags) // flags: s
|
|||
|
||||
crct.op1_out = crct.CH->op1_out;
|
||||
crct.algo = crct.CH->ALGO & 7;
|
||||
crct.algo |= crct.CH->upd_cnt << 4;
|
||||
if (ym2612.OPN.ST.flags & ST_DAC)
|
||||
crct.algo |= 0x80;
|
||||
|
||||
|
@ -1373,6 +1342,7 @@ static int chan_render(int *buffer, int length, int c, UINT32 flags) // flags: s
|
|||
}
|
||||
else
|
||||
ym2612.slot_mask &= ~(0xf << (c*4));
|
||||
crct.CH->upd_cnt = (crct.algo >> 4) & 0x7;
|
||||
|
||||
return (crct.algo & 8) >> 3; // had output
|
||||
}
|
||||
|
@ -1625,9 +1595,10 @@ static void OPNSetPres(int pres)
|
|||
int i;
|
||||
|
||||
/* frequency base */
|
||||
ym2612.OPN.ST.freqbase = (ym2612.OPN.ST.rate) ? ((double)ym2612.OPN.ST.clock / ym2612.OPN.ST.rate) / pres : 0;
|
||||
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) * ym2612.OPN.ST.freqbase;
|
||||
ym2612.OPN.eg_timer_add = (1<<EG_SH) * freqbase;
|
||||
ym2612.OPN.ST.freqbase = 1.0; // freqbase
|
||||
|
||||
/* make time tables */
|
||||
init_timetables( dt_tab );
|
||||
|
|
|
@ -59,7 +59,7 @@ typedef struct
|
|||
UINT8 ssgn;
|
||||
UINT16 ar_ksr; /* 0x32 ar+ksr */
|
||||
UINT16 vol_out; /* 0x34 current output from EG (without LFO) */
|
||||
UINT16 vol_ipol; /* 0x36 interpolator memory */
|
||||
UINT16 pad;
|
||||
} FM_SLOT;
|
||||
|
||||
|
||||
|
@ -79,7 +79,7 @@ typedef struct
|
|||
|
||||
UINT8 kcode; /* +11 key code: */
|
||||
UINT8 fn_h; /* freq latch */
|
||||
UINT8 pad2;
|
||||
UINT8 upd_cnt; /* eg update counter */
|
||||
UINT32 fc; /* fnum,blk:adjusted to sample rate */
|
||||
UINT32 block_fnum; /* current blk/fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#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
|
||||
|
@ -34,7 +33,6 @@
|
|||
.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)
|
||||
|
@ -46,14 +44,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
|
||||
|
||||
|
@ -211,7 +203,6 @@
|
|||
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
|
||||
|
@ -259,14 +250,8 @@
|
|||
|
||||
@ 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
|
||||
|
@ -342,6 +327,9 @@
|
|||
@ 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
|
||||
|
@ -383,6 +371,9 @@
|
|||
|
||||
.macro upd_algo1_m
|
||||
|
||||
cmp r8, #(1<<EG_SH)
|
||||
bge 1f
|
||||
|
||||
@ SLOT3
|
||||
make_eg_out SLOT3
|
||||
cmp r1, #ENV_QUIET
|
||||
|
@ -423,6 +414,9 @@
|
|||
|
||||
.macro upd_algo2_m
|
||||
|
||||
cmp r8, #(1<<EG_SH)
|
||||
bge 1f
|
||||
|
||||
@ SLOT3
|
||||
make_eg_out SLOT3
|
||||
cmp r1, #ENV_QUIET
|
||||
|
@ -464,6 +458,9 @@
|
|||
|
||||
.macro upd_algo3_m
|
||||
|
||||
cmp r8, #(1<<EG_SH)
|
||||
bge 1f
|
||||
|
||||
@ SLOT3
|
||||
make_eg_out SLOT3
|
||||
cmp r1, #ENV_QUIET
|
||||
|
@ -505,6 +502,9 @@
|
|||
|
||||
.macro upd_algo4_m
|
||||
|
||||
cmp r8, #(1<<EG_SH)
|
||||
bge 2f
|
||||
|
||||
@ SLOT3
|
||||
make_eg_out SLOT3
|
||||
cmp r1, #ENV_QUIET
|
||||
|
@ -542,6 +542,9 @@
|
|||
|
||||
.macro upd_algo5_m
|
||||
|
||||
cmp r8, #(1<<EG_SH)
|
||||
bge 2f
|
||||
|
||||
@ SLOT3
|
||||
make_eg_out SLOT3
|
||||
cmp r1, #ENV_QUIET
|
||||
|
@ -582,6 +585,9 @@
|
|||
|
||||
.macro upd_algo6_m
|
||||
|
||||
cmp r8, #(1<<EG_SH)
|
||||
bge 2f
|
||||
|
||||
@ SLOT3
|
||||
make_eg_out SLOT3
|
||||
cmp r1, #ENV_QUIET
|
||||
|
@ -617,6 +623,9 @@
|
|||
|
||||
.macro upd_algo7_m
|
||||
|
||||
cmp r8, #(1<<EG_SH)
|
||||
bge 2f
|
||||
|
||||
@ SLOT3
|
||||
make_eg_out SLOT3
|
||||
cmp r1, #ENV_QUIET
|
||||
|
@ -677,7 +686,7 @@
|
|||
|
||||
|
||||
@ 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
|
||||
|
||||
|
@ -688,47 +697,48 @@ chan_render_loop:
|
|||
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
|
||||
|
||||
tst r12, #8 @ lfo?
|
||||
beq crl_loop
|
||||
|
||||
crl_loop_lfo:
|
||||
ldr r1, [lr, #0x30] @ lfo_cnt
|
||||
ldr r2, [lr, #0x34] @ lfo_inc
|
||||
|
||||
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 lfo_done
|
||||
|
||||
|
||||
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
|
||||
|
@ -748,26 +758,25 @@ ssg_upd_loop:
|
|||
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
|
||||
|
@ -777,96 +786,38 @@ eg_upd_loop:
|
|||
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
|
||||
tst r12, #0x4
|
||||
mov r0, #0
|
||||
bne crl_algo_done
|
||||
|
||||
@ 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
|
||||
cmp r8, #(2<<EG_SH) @ calculate only for operator memory, sample,
|
||||
tstge r12, #0xf000 @ ...feedback
|
||||
beq crl_algo_done
|
||||
|
||||
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
|
||||
|
||||
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]
|
||||
|
||||
#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
|
||||
|
@ -920,6 +871,23 @@ crl_algo7:
|
|||
|
||||
|
||||
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
|
||||
|
@ -944,36 +912,20 @@ crl_algo_done:
|
|||
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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue