📄 fm.c
字号:
/* callback user interrupt handler (IRQ is ON to OFF) */ if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->index,0); }}/* IRQ mask set */INLINE void FM_IRQMASK_SET(FM_ST *ST,int flag){ ST->irqmask = flag; /* IRQ handling check */ FM_STATUS_SET(ST,0); FM_STATUS_RESET(ST,0);}/* ---------- event hander of Phase Generator ---------- *//* Release end -> stop counter */static void FM_EG_Release( FM_SLOT *SLOT ){ SLOT->evc = EG_OFF; SLOT->eve = EG_OFF+1; SLOT->evs = 0;}/* SUSTAIN end -> stop counter */static void FM_EG_SR( FM_SLOT *SLOT ){ SLOT->evs = 0; SLOT->evc = EG_OFF; SLOT->eve = EG_OFF+1;}/* Decay end -> Sustain */static void FM_EG_DR( FM_SLOT *SLOT ){ SLOT->eg_next = FM_EG_SR; SLOT->evc = SLOT->SL; SLOT->eve = EG_DED; SLOT->evs = SLOT->evss;}/* Attack end -> Decay */static void FM_EG_AR( FM_SLOT *SLOT ){ /* next DR */ SLOT->eg_next = FM_EG_DR; SLOT->evc = EG_DST; SLOT->eve = SLOT->SL; SLOT->evs = SLOT->evsd;}#if FM_SEG_SUPPORTstatic void FM_EG_SSG_SR( FM_SLOT *SLOT );/* SEG down side end */static void FM_EG_SSG_DR( FM_SLOT *SLOT ){ if( SLOT->SEG&2){ /* reverce */ SLOT->eg_next = FM_EG_SSG_SR; SLOT->evc = SLOT->SL + (EG_UST - EG_DST); SLOT->eve = EG_UED; SLOT->evs = SLOT->evss; }else{ /* again */ SLOT->evc = EG_DST; } /* hold */ if( SLOT->SEG&1) SLOT->evs = 0;}/* SEG upside side end */static void FM_EG_SSG_SR( FM_SLOT *SLOT ){ if( SLOT->SEG&2){ /* reverce */ SLOT->eg_next = FM_EG_SSG_DR; SLOT->evc = EG_DST; SLOT->eve = EG_DED; SLOT->evs = SLOT->evsd; }else{ /* again */ SLOT->evc = SLOT->SL + (EG_UST - EG_DST); } /* hold check */ if( SLOT->SEG&1) SLOT->evs = 0;}/* SEG Attack end */static void FM_EG_SSG_AR( FM_SLOT *SLOT ){ if( SLOT->SEG&4){ /* start direction */ /* next SSG-SR (upside start ) */ SLOT->eg_next = FM_EG_SSG_SR; SLOT->evc = SLOT->SL + (EG_UST - EG_DST); SLOT->eve = EG_UED; SLOT->evs = SLOT->evss; }else{ /* next SSG-DR (downside start ) */ SLOT->eg_next = FM_EG_SSG_DR; SLOT->evc = EG_DST; SLOT->eve = EG_DED; SLOT->evs = SLOT->evsd; }}#endif /* FM_SEG_SUPPORT *//* ----- key on of SLOT ----- */#define FM_KEY_IS(SLOT) ((SLOT)->eg_next!=FM_EG_Release)INLINE void FM_KEYON(FM_CH *CH , int s ){ FM_SLOT *SLOT = &CH->SLOT[s]; if( !FM_KEY_IS(SLOT) ) { /* restart Phage Generator */ SLOT->Cnt = 0; /* phase -> Attack */#if FM_SEG_SUPPORT if( SLOT->SEG&8 ) SLOT->eg_next = FM_EG_SSG_AR; else#endif SLOT->eg_next = FM_EG_AR; SLOT->evs = SLOT->evsa;#if 0 /* convert decay count to attack count */ /* --- This caused the problem by credit sound of paper boy. --- */ SLOT->evc = EG_AST + DRAR_TABLE[ENV_CURVE[SLOT->evc>>ENV_BITS]];/* + SLOT->evs;*/#else /* reset attack counter */ SLOT->evc = EG_AST;#endif SLOT->eve = EG_AED; }}/* ----- key off of SLOT ----- */INLINE void FM_KEYOFF(FM_CH *CH , int s ){ FM_SLOT *SLOT = &CH->SLOT[s]; if( FM_KEY_IS(SLOT) ) { /* if Attack phase then adjust envelope counter */ if( SLOT->evc < EG_DST ) SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<<ENV_BITS) + EG_DST; /* phase -> Release */ SLOT->eg_next = FM_EG_Release; SLOT->eve = EG_DED; SLOT->evs = SLOT->evsr; }}/* setup Algorythm and PAN connection */static void setup_connection( FM_CH *CH ){ INT32 *carrier = &out_ch[CH->PAN]; /* NONE,LEFT,RIGHT or CENTER */ switch( CH->ALGO ){ case 0: /* PG---S1---S2---S3---S4---OUT */ CH->connect1 = &pg_in2; CH->connect2 = &pg_in3; CH->connect3 = &pg_in4; break; case 1: /* PG---S1-+-S3---S4---OUT */ /* PG---S2-+ */ CH->connect1 = &pg_in3; CH->connect2 = &pg_in3; CH->connect3 = &pg_in4; break; case 2: /* PG---S1------+-S4---OUT */ /* PG---S2---S3-+ */ CH->connect1 = &pg_in4; CH->connect2 = &pg_in3; CH->connect3 = &pg_in4; break; case 3: /* PG---S1---S2-+-S4---OUT */ /* PG---S3------+ */ CH->connect1 = &pg_in2; CH->connect2 = &pg_in4; CH->connect3 = &pg_in4; break; case 4: /* PG---S1---S2-+--OUT */ /* PG---S3---S4-+ */ CH->connect1 = &pg_in2; CH->connect2 = carrier; CH->connect3 = &pg_in4; break; case 5: /* +-S2-+ */ /* PG---S1-+-S3-+-OUT */ /* +-S4-+ */ CH->connect1 = 0; /* special case */ CH->connect2 = carrier; CH->connect3 = carrier; break; case 6: /* PG---S1---S2-+ */ /* PG--------S3-+-OUT */ /* PG--------S4-+ */ CH->connect1 = &pg_in2; CH->connect2 = carrier; CH->connect3 = carrier; break; case 7: /* PG---S1-+ */ /* PG---S2-+-OUT */ /* PG---S3-+ */ /* PG---S4-+ */ CH->connect1 = carrier; CH->connect2 = carrier; CH->connect3 = carrier; } CH->connect4 = carrier;}/* set detune & multiple */INLINE void set_det_mul(FM_ST *ST,FM_CH *CH,FM_SLOT *SLOT,int v){ SLOT->mul = MUL_TABLE[v&0x0f]; SLOT->DT = ST->DT_TABLE[(v>>4)&7]; CH->SLOT[SLOT1].Incr=-1;}/* set total level */INLINE void set_tl(FM_CH *CH,FM_SLOT *SLOT , int v,int csmflag){ v &= 0x7f; v = (v<<7)|v; /* 7bit -> 14bit */ SLOT->TL = (v*EG_ENT)>>14; /* if it is not a CSM channel , latch the total level */ if( !csmflag ) SLOT->TLL = SLOT->TL;}/* set attack rate & key scale */INLINE void set_ar_ksr(FM_CH *CH,FM_SLOT *SLOT,int v,INT32 *ar_table){ SLOT->KSR = 3-(v>>6); SLOT->AR = (v&=0x1f) ? &ar_table[v<<1] : RATE_0; SLOT->evsa = SLOT->AR[SLOT->ksr]; if( SLOT->eg_next == FM_EG_AR ) SLOT->evs = SLOT->evsa; CH->SLOT[SLOT1].Incr=-1;}/* set decay rate */INLINE void set_dr(FM_SLOT *SLOT,int v,INT32 *dr_table){ SLOT->DR = (v&=0x1f) ? &dr_table[v<<1] : RATE_0; SLOT->evsd = SLOT->DR[SLOT->ksr]; if( SLOT->eg_next == FM_EG_DR ) SLOT->evs = SLOT->evsd;}/* set sustain rate */INLINE void set_sr(FM_SLOT *SLOT,int v,INT32 *dr_table){ SLOT->SR = (v&=0x1f) ? &dr_table[v<<1] : RATE_0; SLOT->evss = SLOT->SR[SLOT->ksr]; if( SLOT->eg_next == FM_EG_SR ) SLOT->evs = SLOT->evss;}/* set release rate */INLINE void set_sl_rr(FM_SLOT *SLOT,int v,INT32 *dr_table){ SLOT->SL = SL_TABLE[(v>>4)]; SLOT->RR = &dr_table[((v&0x0f)<<2)|2]; SLOT->evsr = SLOT->RR[SLOT->ksr]; if( SLOT->eg_next == FM_EG_Release ) SLOT->evs = SLOT->evsr;}/* operator output calcrator */#define OP_OUT(PG,EG) SIN_TABLE[(PG/(0x1000000/SIN_ENT))&(SIN_ENT-1)][EG]#define OP_OUTN(PG,EG) NOISE_TABLE[(PG/(0x1000000/SIN_ENT))&(SIN_ENT-1)][EG]/* eg calcration */#if FM_LFO_SUPPORT#define FM_CALC_EG(OUT,SLOT) \{ \ if( (SLOT.evc += SLOT.evs) >= SLOT.eve) \ SLOT.eg_next(&(SLOT)); \ OUT = SLOT.TLL+ENV_CURVE[SLOT.evc>>ENV_BITS]; \ if(SLOT.ams) \ OUT += (SLOT.ams*lfo_amd/LFO_RATE); \}#else#define FM_CALC_EG(OUT,SLOT) \{ \ if( (SLOT.evc += SLOT.evs) >= SLOT.eve) \ SLOT.eg_next(&(SLOT)); \ OUT = SLOT.TLL+ENV_CURVE[SLOT.evc>>ENV_BITS]; \}#endif/* ---------- calcrate one of channel ---------- */INLINE void FM_CALC_CH( FM_CH *CH ){ UINT32 eg_out1,eg_out2,eg_out3,eg_out4; /*envelope output */ /* Phase Generator */#if FM_LFO_SUPPORT INT32 pms = lfo_pmd * CH->pms / LFO_RATE; if(pms) { pg_in1 = (CH->SLOT[SLOT1].Cnt += CH->SLOT[SLOT1].Incr + (INT32)(pms * CH->SLOT[SLOT1].Incr) / PMS_RATE); pg_in2 = (CH->SLOT[SLOT2].Cnt += CH->SLOT[SLOT2].Incr + (INT32)(pms * CH->SLOT[SLOT2].Incr) / PMS_RATE); pg_in3 = (CH->SLOT[SLOT3].Cnt += CH->SLOT[SLOT3].Incr + (INT32)(pms * CH->SLOT[SLOT3].Incr) / PMS_RATE); pg_in4 = (CH->SLOT[SLOT4].Cnt += CH->SLOT[SLOT4].Incr + (INT32)(pms * CH->SLOT[SLOT4].Incr) / PMS_RATE); } else#endif { pg_in1 = (CH->SLOT[SLOT1].Cnt += CH->SLOT[SLOT1].Incr); pg_in2 = (CH->SLOT[SLOT2].Cnt += CH->SLOT[SLOT2].Incr); pg_in3 = (CH->SLOT[SLOT3].Cnt += CH->SLOT[SLOT3].Incr); pg_in4 = (CH->SLOT[SLOT4].Cnt += CH->SLOT[SLOT4].Incr); } /* Envelope Generator */ FM_CALC_EG(eg_out1,CH->SLOT[SLOT1]); FM_CALC_EG(eg_out2,CH->SLOT[SLOT2]); FM_CALC_EG(eg_out3,CH->SLOT[SLOT3]); FM_CALC_EG(eg_out4,CH->SLOT[SLOT4]); /* Connection */ if( eg_out1 < EG_CUT_OFF ) /* SLOT 1 */ { if( CH->FB ){ /* with self feed back */ pg_in1 += (CH->op1_out[0]+CH->op1_out[1])>>CH->FB; CH->op1_out[1] = CH->op1_out[0]; } CH->op1_out[0] = OP_OUT(pg_in1,eg_out1); /* output slot1 */ if( !CH->connect1 ) { /* algorythm 5 */ pg_in2 += CH->op1_out[0]; pg_in3 += CH->op1_out[0]; pg_in4 += CH->op1_out[0]; }else{ /* other algorythm */ *CH->connect1 += CH->op1_out[0]; } } if( eg_out2 < EG_CUT_OFF ) /* SLOT 2 */ *CH->connect2 += OP_OUT(pg_in2,eg_out2); if( eg_out3 < EG_CUT_OFF ) /* SLOT 3 */ *CH->connect3 += OP_OUT(pg_in3,eg_out3); if( eg_out4 < EG_CUT_OFF ) /* SLOT 4 */ *CH->connect4 += OP_OUT(pg_in4,eg_out4);}/* ---------- frequency counter for operater update ---------- */INLINE void CALC_FCSLOT(FM_SLOT *SLOT , int fc , int kc ){ int ksr; /* frequency step counter */ /* SLOT->Incr= (fc+SLOT->DT[kc])*SLOT->mul; */ SLOT->Incr= (fc+SLOT->DT[kc])*SLOT->mul; /* verified on real chip */ ksr = kc >> SLOT->KSR; if( SLOT->ksr != ksr ) { SLOT->ksr = ksr; /* attack , decay rate recalcration */ SLOT->evsa = SLOT->AR[ksr]; SLOT->evsd = SLOT->DR[ksr]; SLOT->evss = SLOT->SR[ksr]; SLOT->evsr = SLOT->RR[ksr]; }}/* ---------- frequency counter ---------- */INLINE void OPN_CALC_FCOUNT(FM_CH *CH ){ if( CH->SLOT[SLOT1].Incr==-1){ int fc = CH->fc; int kc = CH->kcode; CALC_FCSLOT(&CH->SLOT[SLOT1] , fc , kc ); CALC_FCSLOT(&CH->SLOT[SLOT2] , fc , kc ); CALC_FCSLOT(&CH->SLOT[SLOT3] , fc , kc ); CALC_FCSLOT(&CH->SLOT[SLOT4] , fc , kc ); }}/* ----------- initialize time tabls ----------- */static void init_timetables( FM_ST *ST , UINT8 *DTTABLE , int ARRATE , int DRRATE ){ int i,d; double rate; /* DeTune table */ for (d = 0;d <= 3;d++){ for (i = 0;i <= 31;i++){ rate = (double)DTTABLE[d*32 + i] * ST->freqbase * FREQ_RATE; ST->DT_TABLE[d][i] = (INT32) rate; ST->DT_TABLE[d+4][i] = (INT32)-rate; } } /* make Attack & Decay tables */ for (i = 0;i < 4;i++) ST->AR_TABLE[i] = ST->DR_TABLE[i] = 0; for (i = 4;i < 64;i++){ rate = ST->freqbase; /* frequency rate */ if( i < 60 ) rate *= 1.0+(i&3)*0.25; /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */ rate *= 1<<((i>>2)-1); /* b2-5 : shift bit */ rate *= (double)(EG_ENT<<ENV_BITS); ST->AR_TABLE[i] = (INT32)(rate / ARRATE); ST->DR_TABLE[i] = (INT32)(rate / DRRATE); } ST->AR_TABLE[62] = EG_AED; ST->AR_TABLE[63] = EG_AED; for (i = 64;i < 94 ;i++){ /* make for overflow area */ ST->AR_TABLE[i] = ST->AR_TABLE[63]; ST->DR_TABLE[i] = ST->DR_TABLE[63]; }#if 0 for (i = 0;i < 64 ;i++){ LOG(LOG_WAR,("rate %2d , ar %f ms , dr %f ms \n",i, ((double)(EG_ENT<<ENV_BITS) / ST->AR_TABLE[i]) * (1000.0 / ST->rate), ((double)(EG_ENT<<ENV_BITS) / ST->DR_TABLE[i]) * (1000.0 / ST->rate) )); }#endif}/* ---------- reset one of channel ---------- */static void reset_channel( FM_ST *ST , FM_CH *CH , int chan ){ int c,s; ST->mode = 0; /* normal mode */ FM_STATUS_RESET(ST,0xff); ST->TA = 0; ST->TAC = 0; ST->TB = 0; ST->TBC = 0; for( c = 0 ; c < chan ; c++ ) { CH[c].fc = 0; CH[c].PAN = OUTD_CENTER; for(s = 0 ; s < 4 ; s++ ) { CH[c].SLOT[s].SEG = 0; CH[c].SLOT[s].eg_next= FM_EG_Release; CH[c].SLOT[s].evc = EG_OFF; CH[c].SLOT[s].eve = EG_OFF+1; CH[c].SLOT[s].evs = 0; } }}/* ---------- generic table initialize ---------- */static int FMInitTable( void ){ int s,t; double rate; int i,j; double pom; /* allocate total level table plus+minus section */ TL_TABLE = (INT32 *)malloc(2*TL_MAX*sizeof(int)); if( TL_TABLE == 0 ) return 0; /* make total level table */ for (t = 0;t < TL_MAX ;t++){ if(t >= PG_CUT_OFF) rate = 0; /* under cut off area */ else rate = ((1<<TL_BITS)-1)/pow(10,EG_STEP*t/20); /* dB -> voltage */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -