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

📄 fm.c

📁 十七种模拟器源代码 非常有用的作课程设计不可缺少的
💻 C
📖 第 1 页 / 共 5 页
字号:
		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 + -