X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=Pico%2Fsound%2Fym2612.c;h=a619c45f84df7c6eb7e1b2a02900e8d0d613a452;hb=eaa9417a9b52389534f0dcbae6263781ea809ab2;hp=625864c32afcc5abbd056571560d7a0b184cd76b;hpb=d2721b08bb50fd1b112befa4b9f1a918dbd1ca03;p=picodrive.git diff --git a/Pico/sound/ym2612.c b/Pico/sound/ym2612.c index 625864c..a619c45 100644 --- a/Pico/sound/ym2612.c +++ b/Pico/sound/ym2612.c @@ -381,7 +381,7 @@ static const UINT8 dt_tab[4 * 32]={ 5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16, /* FD=3 */ 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, - 8 , 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22 + 8 ,8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22 }; @@ -889,7 +889,7 @@ static void chan_render_loop(chan_rend_context *ct, int *buffer, int length) { 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 */ + 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 { @@ -1152,9 +1152,9 @@ static int chan_render(int *buffer, int length, int c, UINT32 flags) // flags: s UINT32 fn; int kc,fc; + blk = block_fnum >> 11; block_fnum = block_fnum*2 + lfo_fn_table_index_offset; - blk = (block_fnum&0x7000) >> 12; fn = block_fnum & 0xfff; /* keyscale code */ @@ -1203,10 +1203,14 @@ static int chan_render(int *buffer, int length, int c, UINT32 flags) // flags: s /* update phase increment and envelope generator */ INLINE void refresh_fc_eg_slot(FM_SLOT *SLOT, int fc, int kc) { - int ksr; + int ksr, fdt; /* (frequency) phase increment counter */ - SLOT->Incr = ((fc+SLOT->DT[kc])*SLOT->mul) >> 1; + fdt = fc+SLOT->DT[kc]; + /* detect overflow */ +// if (fdt < 0) fdt += fn_table[0x7ff*2] >> (7-blk-1); + if (fdt < 0) fdt += fn_table[0x7ff*2] >> 2; + SLOT->Incr = fdt*SLOT->mul >> 1; ksr = kc >> SLOT->KSR; if( SLOT->ksr != ksr ) @@ -1258,6 +1262,17 @@ INLINE void refresh_fc_eg_chan(FM_CH *CH) } } +INLINE void refresh_fc_eg_chan_sl3(void) +{ + if( ym2612.CH[2].SLOT[SLOT1].Incr==-1) + { + refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT1], ym2612.OPN.SL3.fc[1], ym2612.OPN.SL3.kcode[1] ); + refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT2], ym2612.OPN.SL3.fc[2], ym2612.OPN.SL3.kcode[2] ); + refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT3], ym2612.OPN.SL3.fc[0], ym2612.OPN.SL3.kcode[0] ); + refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT4], ym2612.CH[2].fc , ym2612.CH[2].kcode ); + } +} + /* initialize time tables */ static void init_timetables(const UINT8 *dttable) { @@ -1293,6 +1308,7 @@ static void reset_channels(FM_CH *CH) CH[c].SLOT[s].state= EG_OFF; CH[c].SLOT[s].volume = MAX_ATT_INDEX; } + CH[c].mem_value = CH[c].op1_out = 0; } ym2612.slot_mask = 0; } @@ -1427,7 +1443,6 @@ static void OPNSetPres(int pres) ym2612.OPN.eg_timer_add = (1<AMmasks |= 1<AMmasks &= ~(1<>3; + UINT32 fn = (((UINT32)( (CH->fn_h)&7))<<8) + v; + UINT8 blk = CH->fn_h>>3; /* keyscale code */ CH->kcode = (blk<<2) | opn_fktable[fn >> 7]; /* phase increment counter */ @@ -1518,7 +1533,7 @@ static int OPNWriteReg(int r, int v) } break; case 1: /* 0xa4-0xa6 : FNUM2,BLK */ - ym2612.OPN.ST.fn_h = v&0x3f; + CH->fn_h = v&0x3f; ret = 0; break; case 2: /* 0xa8-0xaa : 3CH FNUM1 */ @@ -1530,7 +1545,7 @@ static int OPNWriteReg(int r, int v) ym2612.OPN.SL3.kcode[c]= (blk<<2) | opn_fktable[fn >> 7]; /* phase increment counter */ ym2612.OPN.SL3.fc[c] = fn_table[fn*2]>>(7-blk); - ym2612.OPN.SL3.block_fnum[c] = fn; + ym2612.OPN.SL3.block_fnum[c] = (blk<<11) | fn; ym2612.CH[2].SLOT[SLOT1].Incr=-1; } break; @@ -1618,16 +1633,10 @@ int YM2612UpdateOne_(int *buffer, int length, int stereo, int is_buf_empty) refresh_fc_eg_chan( &ym2612.CH[0] ); refresh_fc_eg_chan( &ym2612.CH[1] ); if( (ym2612.OPN.ST.mode & 0xc0) ) - { /* 3SLOT MODE */ - if( ym2612.CH[2].SLOT[SLOT1].Incr==-1) - { - refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT1], ym2612.OPN.SL3.fc[1], ym2612.OPN.SL3.kcode[1] ); - refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT2], ym2612.OPN.SL3.fc[2], ym2612.OPN.SL3.kcode[2] ); - refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT3], ym2612.OPN.SL3.fc[0], ym2612.OPN.SL3.kcode[0] ); - refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT4], ym2612.CH[2].fc , ym2612.CH[2].kcode ); - } - } else refresh_fc_eg_chan( &ym2612.CH[2] ); + refresh_fc_eg_chan_sl3(); + else + refresh_fc_eg_chan( &ym2612.CH[2] ); refresh_fc_eg_chan( &ym2612.CH[3] ); refresh_fc_eg_chan( &ym2612.CH[4] ); refresh_fc_eg_chan( &ym2612.CH[5] ); @@ -1872,6 +1881,7 @@ void YM2612PicoStateLoad_(void) ym2612.slot_mask = 0xffffff; } +/* rather stupid design because I wanted to fit in unused register "space" */ typedef struct { UINT32 state_phase; @@ -1887,20 +1897,34 @@ typedef struct UINT8 unused; int TAT; int TBT; - UINT32 eg_cnt; + UINT32 eg_cnt; // 10 UINT32 eg_timer; UINT32 lfo_cnt; UINT16 lfo_ampm; UINT16 unused2; + UINT32 keyon_field; // 20 + UINT32 kcode_fc_sl3_3; } ym_save_addon; +typedef struct +{ + UINT16 block_fnum[6]; + UINT16 block_fnum_sl3[3]; + UINT16 unused; +} ym_save_addon2; + + void YM2612PicoStateSave2(int tat, int tbt) { ym_save_addon_slot ss; + ym_save_addon2 sa2; ym_save_addon sa; unsigned char *ptr; int c, s; + memset(&sa, 0, sizeof(sa)); + memset(&sa2, 0, sizeof(sa2)); + // chans 1,2,3 ptr = &ym2612.REGS[0x0b8]; for (c = 0; c < 3; c++) @@ -1908,9 +1932,12 @@ void YM2612PicoStateSave2(int tat, int tbt) for (s = 0; s < 4; s++) { ss.state_phase = (ym2612.CH[c].SLOT[s].state << 29) | (ym2612.CH[c].SLOT[s].phase >> 3); ss.volume = ym2612.CH[c].SLOT[s].volume; + if (ym2612.CH[c].SLOT[s].key) + sa.keyon_field |= 1 << (c*4 + s); memcpy(ptr, &ss, 6); ptr += 6; } + sa2.block_fnum[c] = ym2612.CH[c].block_fnum; } // chans 4,5,6 ptr = &ym2612.REGS[0x1b8]; @@ -1919,38 +1946,52 @@ void YM2612PicoStateSave2(int tat, int tbt) for (s = 0; s < 4; s++) { ss.state_phase = (ym2612.CH[c].SLOT[s].state << 29) | (ym2612.CH[c].SLOT[s].phase >> 3); ss.volume = ym2612.CH[c].SLOT[s].volume; + if (ym2612.CH[c].SLOT[s].key) + sa.keyon_field |= 1 << (c*4 + s); memcpy(ptr, &ss, 6); ptr += 6; } + sa2.block_fnum[c] = ym2612.CH[c].block_fnum; + } + for (c = 0; c < 3; c++) + { + sa2.block_fnum_sl3[c] = ym2612.OPN.SL3.block_fnum[c]; } + + memcpy(&ym2612.REGS[0], &sa2, sizeof(sa2)); // 0x20 max + // other things ptr = &ym2612.REGS[0x100]; sa.magic = 0x41534d59; // 'YMSA' sa.address = ym2612.OPN.ST.address; sa.status = ym2612.OPN.ST.status; sa.addr_A1 = ym2612.addr_A1; - sa.unused = 0; sa.TAT = tat; sa.TBT = tbt; sa.eg_cnt = ym2612.OPN.eg_cnt; sa.eg_timer = ym2612.OPN.eg_timer; sa.lfo_cnt = ym2612.OPN.lfo_cnt; sa.lfo_ampm = g_lfo_ampm; - sa.unused2 = 0; memcpy(ptr, &sa, sizeof(sa)); // 0x30 max } int YM2612PicoStateLoad2(int *tat, int *tbt) { ym_save_addon_slot ss; + ym_save_addon2 sa2; ym_save_addon sa; unsigned char *ptr; + UINT32 fn; + UINT8 blk; int c, s; ptr = &ym2612.REGS[0x100]; memcpy(&sa, ptr, sizeof(sa)); // 0x30 max if (sa.magic != 0x41534d59) return -1; + ptr = &ym2612.REGS[0]; + memcpy(&sa2, ptr, sizeof(sa2)); + ym2612.OPN.ST.address = sa.address; ym2612.OPN.ST.status = sa.status; ym2612.addr_A1 = sa.addr_A1; @@ -1970,8 +2011,16 @@ int YM2612PicoStateLoad2(int *tat, int *tbt) ym2612.CH[c].SLOT[s].state = ss.state_phase >> 29; ym2612.CH[c].SLOT[s].phase = ss.state_phase << 3; ym2612.CH[c].SLOT[s].volume = ss.volume; + ym2612.CH[c].SLOT[s].key = (sa.keyon_field & (1 << (c*4 + s))) ? 1 : 0; + ym2612.CH[c].SLOT[s].ksr = (UINT8)-1; ptr += 6; } + ym2612.CH[c].SLOT[SLOT1].Incr=-1; + ym2612.CH[c].block_fnum = sa2.block_fnum[c]; + fn = ym2612.CH[c].block_fnum & 0x7ff; + blk = ym2612.CH[c].block_fnum >> 11; + ym2612.CH[c].kcode= (blk<<2) | opn_fktable[fn >> 7]; + ym2612.CH[c].fc = fn_table[fn*2]>>(7-blk); } // chans 4,5,6 ptr = &ym2612.REGS[0x1b8]; @@ -1982,8 +2031,24 @@ int YM2612PicoStateLoad2(int *tat, int *tbt) ym2612.CH[c].SLOT[s].state = ss.state_phase >> 29; ym2612.CH[c].SLOT[s].phase = ss.state_phase << 3; ym2612.CH[c].SLOT[s].volume = ss.volume; + ym2612.CH[c].SLOT[s].key = (sa.keyon_field & (1 << (c*4 + s))) ? 1 : 0; + ym2612.CH[c].SLOT[s].ksr = (UINT8)-1; ptr += 6; } + ym2612.CH[c].SLOT[SLOT1].Incr=-1; + ym2612.CH[c].block_fnum = sa2.block_fnum[c]; + fn = ym2612.CH[c].block_fnum & 0x7ff; + blk = ym2612.CH[c].block_fnum >> 11; + ym2612.CH[c].kcode= (blk<<2) | opn_fktable[fn >> 7]; + ym2612.CH[c].fc = fn_table[fn*2]>>(7-blk); + } + for (c = 0; c < 3; c++) + { + ym2612.OPN.SL3.block_fnum[c] = sa2.block_fnum_sl3[c]; + fn = ym2612.OPN.SL3.block_fnum[c] & 0x7ff; + blk = ym2612.OPN.SL3.block_fnum[c] >> 11; + ym2612.OPN.SL3.kcode[c]= (blk<<2) | opn_fktable[fn >> 7]; + ym2612.OPN.SL3.fc[c] = fn_table[fn*2]>>(7-blk); } return 0;