⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fm.c

📁 著名ARC模拟器源码,包括多个平台
💻 C
📖 第 1 页 / 共 5 页
字号:
		/* 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 + -