📄 fm.c
字号:
TL_TABLE[ t] = (int)rate; TL_TABLE[TL_MAX+t] = -TL_TABLE[t];/* LOG(LOG_INF,("TotalLevel(%3d) = %x\n",t,TL_TABLE[t]));*/ } /* make sinwave table (pointer of total level) */ for (s = 1;s <= SIN_ENT/4;s++){ pom = sin(2.0*PI*s/SIN_ENT); /* sin */ pom = 20*log10(1/pom); /* -> decibel */ j = (int)(pom / EG_STEP); /* TL_TABLE steps */ /* cut off check */ if(j > PG_CUT_OFF) j = PG_CUT_OFF; /* degree 0 - 90 , degree 180 - 90 : plus section */ SIN_TABLE[ s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j]; /* degree 180 - 270 , degree 360 - 270 : minus section */ SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT -s] = &TL_TABLE[TL_MAX+j]; /* LOG(LOG_INF,("sin(%3d) = %f:%f db\n",s,pom,(double)j * EG_STEP)); */ } /* degree 0 = degree 180 = off */ SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2] = &TL_TABLE[PG_CUT_OFF]; /* envelope counter -> envelope output table */ for (i=0; i<EG_ENT; i++) { /* ATTACK curve */ /* !!!!! preliminary !!!!! */ pom = pow( ((double)(EG_ENT-1-i)/EG_ENT) , 8 ) * EG_ENT; /* if( pom >= EG_ENT ) pom = EG_ENT-1; */ ENV_CURVE[i] = (int)pom; /* DECAY ,RELEASE curve */ ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i;#if FM_SEG_SUPPORT /* DECAY UPSIDE (SSG ENV) */ ENV_CURVE[(EG_UST>>ENV_BITS)+i]= EG_ENT-1-i;#endif } /* off */ ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1; /* decay to reattack envelope converttable */ j = EG_ENT-1; for (i=0; i<EG_ENT; i++) { while( j && (ENV_CURVE[j] < i) ) j--; DRAR_TABLE[i] = j<<ENV_BITS; /* LOG(LOG_INF,("DR %06X = %06X,AR=%06X\n",i,DRAR_TABLE[i],ENV_CURVE[DRAR_TABLE[i]>>ENV_BITS] )); */ } return 1;}static void FMCloseTable( void ){ if( TL_TABLE ) free( TL_TABLE ); return;}/* OPN/OPM Mode Register Write */INLINE void FMSetMode( FM_ST *ST ,int n,int v ){ /* b7 = CSM MODE */ /* b6 = 3 slot mode */ /* b5 = reset b */ /* b4 = reset a */ /* b3 = timer enable b */ /* b2 = timer enable a */ /* b1 = load b */ /* b0 = load a */ ST->mode = v; /* reset Timer b flag */ if( v & 0x20 ) FM_STATUS_RESET(ST,0x02); /* reset Timer a flag */ if( v & 0x10 ) FM_STATUS_RESET(ST,0x01); /* load b */ if( v & 0x02 ) { if( ST->TBC == 0 ) { ST->TBC = ( 256-ST->TB)<<4; /* External timer handler */ if (ST->Timer_Handler) (ST->Timer_Handler)(n,1,ST->TBC,ST->TimerBase); } }else if (ST->timermodel == FM_TIMER_INTERVAL) { /* stop interbval timer */ if( ST->TBC != 0 ) { ST->TBC = 0; if (ST->Timer_Handler) (ST->Timer_Handler)(n,1,0,ST->TimerBase); } } /* load a */ if( v & 0x01 ) { if( ST->TAC == 0 ) { ST->TAC = (1024-ST->TA); /* External timer handler */ if (ST->Timer_Handler) (ST->Timer_Handler)(n,0,ST->TAC,ST->TimerBase); } }else if (ST->timermodel == FM_TIMER_INTERVAL) { /* stop interbval timer */ if( ST->TAC != 0 ) { ST->TAC = 0; if (ST->Timer_Handler) (ST->Timer_Handler)(n,0,0,ST->TimerBase); } }}/* Timer A Overflow */INLINE void TimerAOver(FM_ST *ST){ /* status set if enabled */ if(ST->mode & 0x04) FM_STATUS_SET(ST,0x01); /* clear or reload the counter */ if (ST->timermodel == FM_TIMER_INTERVAL) { ST->TAC = (1024-ST->TA); if (ST->Timer_Handler) (ST->Timer_Handler)(ST->index,0,ST->TAC,ST->TimerBase); } else ST->TAC = 0;}/* Timer B Overflow */INLINE void TimerBOver(FM_ST *ST){ /* status set if enabled */ if(ST->mode & 0x08) FM_STATUS_SET(ST,0x02); /* clear or reload the counter */ if (ST->timermodel == FM_TIMER_INTERVAL) { ST->TBC = ( 256-ST->TB)<<4; if (ST->Timer_Handler) (ST->Timer_Handler)(ST->index,1,ST->TBC,ST->TimerBase); } else ST->TBC = 0;}/* CSM Key Controll */INLINE void CSMKeyControll(FM_CH *CH){ /* all key off */ /* FM_KEYOFF(CH,SLOT1); */ /* FM_KEYOFF(CH,SLOT2); */ /* FM_KEYOFF(CH,SLOT3); */ /* FM_KEYOFF(CH,SLOT4); */ /* total level latch */ CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL; CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL; CH->SLOT[SLOT3].TLL = CH->SLOT[SLOT3].TL; CH->SLOT[SLOT4].TLL = CH->SLOT[SLOT4].TL; /* all key on */ FM_KEYON(CH,SLOT1); FM_KEYON(CH,SLOT2); FM_KEYON(CH,SLOT3); FM_KEYON(CH,SLOT4);}#if BUILD_OPN/***********************************************************//* OPN unit *//***********************************************************//* OPN 3slot struct */typedef struct opn_3slot { UINT32 fc[3]; /* fnum3,blk3 :calcrated */ UINT8 fn_h[3]; /* freq3 latch */ UINT8 kcode[3]; /* key code : */}FM_3SLOT;/* OPN/A/B common state */typedef struct opn_f { UINT8 type; /* chip type */ FM_ST ST; /* general state */ FM_3SLOT SL3; /* 3 slot mode state */ FM_CH *P_CH; /* pointer of CH */ UINT32 FN_TABLE[2048]; /* fnumber -> increment counter */#if FM_LFO_SUPPORT /* LFO */ UINT32 LFOCnt; UINT32 LFOIncr; UINT32 LFO_FREQ[8];/* LFO FREQ table */#endif} FM_OPN;/* OPN key frequency number -> key code follow table *//* fnum higher 4bit -> keycode lower 2bit */static const UINT8 OPN_FKTABLE[16]={0,0,0,0,0,0,0,1,2,3,3,3,3,3,3,3};#if FM_LFO_SUPPORT/* OPN LFO waveform table */static INT32 OPN_LFO_wave[LFO_ENT];#endifstatic int OPNInitTable(void){ int i;#if FM_LFO_SUPPORT /* LFO wave table */ for(i=0;i<LFO_ENT;i++) { OPN_LFO_wave[i]= i<LFO_ENT/2 ? i*LFO_RATE/(LFO_ENT/2) : (LFO_ENT-i)*LFO_RATE/(LFO_ENT/2); }#endif return FMInitTable();}/* ---------- priscaler set(and make time tables) ---------- */static void OPNSetPris(FM_OPN *OPN , int pris , int TimerPris, int SSGpris){ int i; /* frequency base */ OPN->ST.freqbase = (OPN->ST.rate) ? ((double)OPN->ST.clock / OPN->ST.rate) / pris : 0; /* Timer base time */ OPN->ST.TimerBase = 1.0/((double)OPN->ST.clock / (double)TimerPris); /* SSG part priscaler set */ if( SSGpris ) SSGClk( OPN->ST.index, OPN->ST.clock * 2 / SSGpris ); /* make time tables */ init_timetables( &OPN->ST , OPN_DTTABLE , OPN_ARRATE , OPN_DRRATE ); /* make fnumber -> increment counter table */ for( i=0 ; i < 2048 ; i++ ) { /* it is freq table for octave 7 */ /* opn freq counter = 20bit */ OPN->FN_TABLE[i] = (UINT32)( (double)i * OPN->ST.freqbase * FREQ_RATE * (1<<7) / 2 ); }#if FM_LFO_SUPPORT /* LFO freq. table */ { /* 3.98Hz,5.56Hz,6.02Hz,6.37Hz,6.88Hz,9.63Hz,48.1Hz,72.2Hz @ 8MHz */#define FM_LF(Hz) ((double)LFO_ENT*(1<<LFO_SHIFT)*(Hz)/(8000000.0/144)) static const double freq_table[8] = { FM_LF(3.98),FM_LF(5.56),FM_LF(6.02),FM_LF(6.37),FM_LF(6.88),FM_LF(9.63),FM_LF(48.1),FM_LF(72.2) };#undef FM_LF for(i=0;i<8;i++) { OPN->LFO_FREQ[i] = (UINT32)(freq_table[i] * OPN->ST.freqbase); } }#endif/* LOG(LOG_INF,("OPN %d set priscaler %d\n",OPN->ST.index,pris));*/}/* ---------- write a OPN mode register 0x20-0x2f ---------- */static void OPNWriteMode(FM_OPN *OPN, int r, int v){ UINT8 c; FM_CH *CH; switch(r){ case 0x21: /* Test */ break;#if FM_LFO_SUPPORT case 0x22: /* LFO FREQ (YM2608/YM2612) */ if( OPN->type & TYPE_LFOPAN ) { OPN->LFOIncr = (v&0x08) ? OPN->LFO_FREQ[v&7] : 0; cur_chip = NULL; } break;#endif case 0x24: /* timer A High 8*/ OPN->ST.TA = (OPN->ST.TA & 0x03)|(((int)v)<<2); break; case 0x25: /* timer A Low 2*/ OPN->ST.TA = (OPN->ST.TA & 0x3fc)|(v&3); break; case 0x26: /* timer B */ OPN->ST.TB = v; break; case 0x27: /* mode , timer controll */ FMSetMode( &(OPN->ST),OPN->ST.index,v ); break; case 0x28: /* key on / off */ c = v&0x03; if( c == 3 ) break; if( (v&0x04) && (OPN->type & TYPE_6CH) ) c+=3; CH = OPN->P_CH; CH = &CH[c]; /* csm mode */ /* if( c == 2 && (OPN->ST.mode & 0x80) ) break; */ if(v&0x10) FM_KEYON(CH,SLOT1); else FM_KEYOFF(CH,SLOT1); if(v&0x20) FM_KEYON(CH,SLOT2); else FM_KEYOFF(CH,SLOT2); if(v&0x40) FM_KEYON(CH,SLOT3); else FM_KEYOFF(CH,SLOT3); if(v&0x80) FM_KEYON(CH,SLOT4); else FM_KEYOFF(CH,SLOT4);/* LOG(LOG_INF,("OPN %d:%d : KEY %02X\n",n,c,v&0xf0));*/ break; }}/* ---------- write a OPN register (0x30-0xff) ---------- */static void OPNWriteReg(FM_OPN *OPN, int r, int v){ UINT8 c; FM_CH *CH; FM_SLOT *SLOT; /* 0x30 - 0xff */ if( (c = OPN_CHAN(r)) == 3 ) return; /* 0xX3,0xX7,0xXB,0xXF */ if( (r >= 0x100) /* && (OPN->type & TYPE_6CH) */ ) c+=3; CH = OPN->P_CH; CH = &CH[c]; SLOT = &(CH->SLOT[OPN_SLOT(r)]); switch( r & 0xf0 ) { case 0x30: /* DET , MUL */ set_det_mul(&OPN->ST,CH,SLOT,v); break; case 0x40: /* TL */ set_tl(CH,SLOT,v,(c == 2) && (OPN->ST.mode & 0x80) ); break; case 0x50: /* KS, AR */ set_ar_ksr(CH,SLOT,v,OPN->ST.AR_TABLE); break; case 0x60: /* DR */ /* bit7 = AMS_ON ENABLE(YM2612) */ set_dr(SLOT,v,OPN->ST.DR_TABLE);#if FM_LFO_SUPPORT if( OPN->type & TYPE_LFOPAN) { SLOT->amon = v>>7; SLOT->ams = CH->ams * SLOT->amon; }#endif break; case 0x70: /* SR */ set_sr(SLOT,v,OPN->ST.DR_TABLE); break; case 0x80: /* SL, RR */ set_sl_rr(SLOT,v,OPN->ST.DR_TABLE); break; case 0x90: /* SSG-EG *//* #if !FM_SEG_SUPPORT *//* if(v&0x08) LOG(LOG_ERR,("OPN %d,%d,%d :SSG-TYPE envelope selected (not supported )\n",OPN->ST.index,c,OPN_SLOT(r))); *//* #endif */ SLOT->SEG = v&0x0f; break; case 0xa0: switch( OPN_SLOT(r) ){ case 0: /* 0xa0-0xa2 : FNUM1 */ { UINT32 fn = (((UINT32)( (CH->fn_h)&7))<<8) + v; UINT8 blk = CH->fn_h>>3; /* make keyscale code */ CH->kcode = (blk<<2)|OPN_FKTABLE[(fn>>7)]; /* make basic increment counter 32bit = 1 cycle */ CH->fc = OPN->FN_TABLE[fn]>>(7-blk); CH->SLOT[SLOT1].Incr=-1; } break; case 1: /* 0xa4-0xa6 : FNUM2,BLK */ CH->fn_h = v&0x3f; break; case 2: /* 0xa8-0xaa : 3CH FNUM1 */ if( r < 0x100) { UINT32 fn = (((UINT32)(OPN->SL3.fn_h[c]&7))<<8) + v; UINT8 blk = OPN->SL3.fn_h[c]>>3; /* make keyscale code */ OPN->SL3.kcode[c]= (blk<<2)|OPN_FKTABLE[(fn>>7)]; /* make basic increment counter 32bit = 1 cycle */ OPN->SL3.fc[c] = OPN->FN_TABLE[fn]>>(7-blk); (OPN->P_CH)[2].SLOT[SLOT1].Incr=-1; } break; case 3: /* 0xac-0xae : 3CH FNUM2,BLK */ if( r < 0x100) OPN->SL3.fn_h[c] = v&0x3f; break; } break; case 0xb0: switch( OPN_SLOT(r) ){ case 0: /* 0xb0-0xb2 : FB,ALGO */ { int feedback = (v>>3)&7; CH->ALGO = v&7; CH->FB = feedback ? 8+1 - feedback : 0; setup_connection( CH ); } break; case 1: /* 0xb4-0xb6 : L , R , AMS , PMS (YM2612/YM2608) */ if( OPN->type & TYPE_LFOPAN) {#if FM_LFO_SUPPORT /* b0-2 PMS */ /* 0,3.4,6.7,10,14,20,40,80(cent) */ static const double pmd_table[8]={0,3.4,6.7,10,14,20,40,80}; static const int amd_table[4]={(int)(0/EG_STEP),(int)(1.4/EG_STEP),(int)(5.9/EG_STEP),(int)(11.8/EG_STEP) }; CH->pms = (INT32)( (1.5/1200.0)*pmd_table[v & 7] * PMS_RATE); /* b4-5 AMS */ /* 0 , 1.4 , 5.9 , 11.8(dB) */ CH->ams = amd_table[(v>>4) & 0x03]; CH->SLOT[SLOT1].ams = CH->ams * CH->SLOT[SLOT1].amon; CH->SLOT[SLOT2].ams = CH->ams * CH->SLOT[SLOT2].amon; CH->SLOT[SLOT3].ams = CH->ams * CH->SLOT[SLOT3].amon; CH->SLOT[SLOT4].ams = CH->ams * CH->SLOT[SLOT4].amon;#endif /* PAN */ CH->PAN = (v>>6)&0x03; /* PAN : b6 = R , b7 = L */ setup_connection( CH ); /* LOG(LOG_INF,("OPN %d,%d : PAN %d\n",n,c,CH->PAN));*/ } break; } break; }}#endif /* BUILD_OPN */#if BUILD_YM2203/*******************************************************************************//* YM2203 local section *//*******************************************************************************//* here's the virtual YM2203(OPN) */typedef struct ym2203_f { FM_OPN OPN; /* OPN state */ FM_CH CH[3]; /* channel state */} YM2203;static YM2203 *FM2203=NULL; /* array of YM2203's */static int YM2203NumChips; /* total chip *//* ---------- update one of chip ----------- */void YM2203UpdateOne(int num, INT16 *buffer, int length){ YM2203 *F2203 = &(FM2203[num]); FM_OPN *OPN = &(FM2203[num].OPN); int i; FM_CH *ch; FMSAMPLE *buf = buffer; cur_chip = (void *)F2203; State = &F2203->OPN.ST; cch[0] = &F2203->CH[0]; cch[1] = &F2203->CH[1]; cch[2] = &F2203->CH[2];#if FM_LFO_SUPPORT /* LFO */ lfo_amd = lfo_pmd = 0;#endif /* frequency counter channel A */ OPN_CALC_FCOUNT( cch[0] ); /* frequency counter channel B */ OPN_CALC_FCOUNT( cch[1] ); /* frequency counter channel C */ if( (State->mode & 0xc0) ){ /* 3SLOT MODE */ if( cch[2]->SLOT[SLOT1].Incr==-1){ /* 3 slot mode */ CALC_FCSLOT(&cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); CALC_FCSLOT(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); CALC_FCSLOT(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); CALC_FCSLOT(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode ); } }else OPN_CALC_FCOUNT( cch[2] ); for( i=0; i < length ; i++ ) { /* channel A channel B channel C */ out_ch[OUTD_CENTER] = 0; /* calcrate FM */ for( ch=cch[0] ; ch <= cch[2] ; ch++) FM_CALC_CH( ch );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -