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

📄 fm.c

📁 十七种模拟器源代码 非常有用的作课程设计不可缺少的
💻 C
📖 第 1 页 / 共 5 页
字号:
		/* limit check */		Limit( out_ch[OUTD_CENTER] , FM_MAXOUT, FM_MINOUT );		/* store to sound buffer */		buf[i] = out_ch[OUTD_CENTER] >> FM_OUTSB;		/* timer controll */		INTERNAL_TIMER_A( State , cch[2] )	}	INTERNAL_TIMER_B(State,length)}/* ---------- reset one of chip ---------- */void YM2203ResetChip(int num){	int i;	FM_OPN *OPN = &(FM2203[num].OPN);	/* Reset Priscaler */	OPNSetPris( OPN , 6*12 , 6*12 ,4); /* 1/6 , 1/4 */	/* reset SSG section */	SSGReset(OPN->ST.index);	/* status clear */	FM_IRQMASK_SET(&OPN->ST,0x03);	OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */	reset_channel( &OPN->ST , FM2203[num].CH , 3 );	/* reset OPerator paramater */	for(i = 0xb6 ; i >= 0xb4 ; i-- ) OPNWriteReg(OPN,i,0xc0); /* PAN RESET */	for(i = 0xb2 ; i >= 0x30 ; i-- ) OPNWriteReg(OPN,i,0);	for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0);}/* ----------  Initialize YM2203 emulator(s) ----------    *//* 'num' is the number of virtual YM2203's to allocate     *//* 'rate' is sampling rate and 'bufsiz' is the size of the *//* buffer that should be updated at each interval          */int YM2203Init(int num, int clock, int rate,               FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler){	int i;	if (FM2203) return (-1);	/* duplicate init. */	cur_chip = NULL;	/* hiro-shi!! */	YM2203NumChips = num;	/* allocate ym2203 state space */	if( (FM2203 = (YM2203 *)malloc(sizeof(YM2203) * YM2203NumChips))==NULL)		return (-1);	/* clear */	memset(FM2203,0,sizeof(YM2203) * YM2203NumChips);	/* allocate total level table (128kb space) */	if( !OPNInitTable() )	{		free( FM2203 );		return (-1);	}	for ( i = 0 ; i < YM2203NumChips; i++ ) {		FM2203[i].OPN.ST.index = i;		FM2203[i].OPN.type = TYPE_YM2203;		FM2203[i].OPN.P_CH = FM2203[i].CH;		FM2203[i].OPN.ST.clock = clock;		FM2203[i].OPN.ST.rate = rate;		/* FM2203[i].OPN.ST.irq = 0; */		/* FM2203[i].OPN.ST.satus = 0; */		FM2203[i].OPN.ST.timermodel = FM_TIMER_INTERVAL;		/* Extend handler */		FM2203[i].OPN.ST.Timer_Handler = TimerHandler;		FM2203[i].OPN.ST.IRQ_Handler   = IRQHandler;		YM2203ResetChip(i);	}	return(0);}/* ---------- shut down emurator ----------- */void YM2203Shutdown(void){    if (!FM2203) return;	FMCloseTable();	free(FM2203);	FM2203 = NULL;}/* ---------- YM2203 I/O interface ---------- */int YM2203Write(int n,int a,UINT8 v){	FM_OPN *OPN = &(FM2203[n].OPN);	if( !(a&1) )	{	/* address port */		OPN->ST.address = v & 0xff;		/* Write register to SSG emurator */		if( v < 16 ) SSGWrite(n,0,v);		switch(OPN->ST.address)		{		case 0x2d:	/* divider sel */			OPNSetPris( OPN, 6*12, 6*12 ,4); /* OPN 1/6 , SSG 1/4 */			break;		case 0x2e:	/* divider sel */			OPNSetPris( OPN, 3*12, 3*12,2); /* OPN 1/3 , SSG 1/2 */			break;		case 0x2f:	/* divider sel */			OPNSetPris( OPN, 2*12, 2*12,1); /* OPN 1/2 , SSG 1/1 */			break;		}	}	else	{	/* data port */		int addr = OPN->ST.address;		switch( addr & 0xf0 )		{		case 0x00:	/* 0x00-0x0f : SSG section */			/* Write data to SSG emurator */			SSGWrite(n,a,v);			break;		case 0x20:	/* 0x20-0x2f : Mode section */			YM2203UpdateReq(n);			/* write register */			 OPNWriteMode(OPN,addr,v);			break;		default:	/* 0x30-0xff : OPN section */			YM2203UpdateReq(n);			/* write register */			 OPNWriteReg(OPN,addr,v);		}	}	return OPN->ST.irq;}UINT8 YM2203Read(int n,int a){	YM2203 *F2203 = &(FM2203[n]);	int addr = F2203->OPN.ST.address;	int ret = 0;	if( !(a&1) )	{	/* status port */		ret = F2203->OPN.ST.status;	}	else	{	/* data port (ONLY SSG) */		if( addr < 16 ) ret = SSGRead(n);	}	return ret;}int YM2203TimerOver(int n,int c){	YM2203 *F2203 = &(FM2203[n]);	if( c )	{	/* Timer B */		TimerBOver( &(F2203->OPN.ST) );	}	else	{	/* Timer A */		YM2203UpdateReq(n);		/* timer update */		TimerAOver( &(F2203->OPN.ST) );		/* CSM mode key,TL controll */		if( F2203->OPN.ST.mode & 0x80 )		{	/* CSM mode total level latch and auto key on */			CSMKeyControll( &(F2203->CH[2]) );		}	}	return F2203->OPN.ST.irq;}#endif /* BUILD_YM2203 */#if (BUILD_YM2608||BUILD_OPNB)/* adpcm type A struct */typedef struct adpcm_state {	UINT8 flag;			/* port state        */	UINT8 flagMask;		/* arrived flag mask */	UINT8 now_data;	UINT32 now_addr;	UINT32 now_step;	UINT32 step;	UINT32 start;	UINT32 end;	int IL;	int volume;					/* calcrated mixing level */	INT32 *pan;					/* &out_ch[OPN_xxxx] */	int /*adpcmm,*/ adpcmx, adpcmd;	int adpcml;					/* hiro-shi!! */}ADPCM_CH;/* here's the virtual YM2610 */typedef struct ym2610_f {	FM_OPN OPN;				/* OPN state    */	FM_CH CH[6];			/* channel state */	int address1;			/* address register1 */	/* ADPCM-A unit */	UINT8 *pcmbuf;			/* pcm rom buffer */	UINT32 pcm_size;			/* size of pcm rom */	INT32 *adpcmTL;					/* adpcmA total level */	ADPCM_CH adpcm[6];				/* adpcm channels */	UINT32 adpcmreg[0x30];	/* registers */	UINT8 adpcm_arrivedEndAddress;	/* Delta-T ADPCM unit */	YM_DELTAT deltaT;} YM2610;/* here's the virtual YM2608 */typedef YM2610 YM2608;#endif /* (BUILD_YM2608||BUILD_OPNB) */#if BUILD_FM_ADPCMA/***************************************************************//*    ADPCMA units are made by Hiromitsu Shioya (MMSND)         *//***************************************************************//**** YM2610 ADPCM defines ****/#define ADPCMA_MIXING_LEVEL  (3) /* ADPCMA mixing level   */#define ADPCM_SHIFT    (16)      /* frequency step rate   */#define ADPCMA_ADDRESS_SHIFT 8   /* adpcm A address shift *//*#define ADPCMA_DECODE_RANGE 1024 */#define ADPCMA_DECODE_RANGE 2048#define ADPCMA_DECODE_MIN (-(ADPCMA_DECODE_RANGE*ADPCMA_MIXING_LEVEL))#define ADPCMA_DECODE_MAX ((ADPCMA_DECODE_RANGE*ADPCMA_MIXING_LEVEL)-1)#define ADPCMA_VOLUME_DIV 1static UINT8 *pcmbufA;static UINT32 pcmsizeA;/************************************************************//************************************************************//* --------------------- subroutines  --------------------- *//************************************************************//************************************************************//************************//*    ADPCM A tables    *//************************/static int jedi_table[(48+1)*16];static int decode_tableA1[16] = {  -1*16, -1*16, -1*16, -1*16, 2*16, 5*16, 7*16, 9*16,  -1*16, -1*16, -1*16, -1*16, 2*16, 5*16, 7*16, 9*16};/* 0.9 , 0.9 , 0.9 , 0.9 , 1.2 , 1.6 , 2.0 , 2.4 *//* 8 = -1 , 2 5 8 11 *//* 9 = -1 , 2 5 9 13 *//* 10= -1 , 2 6 10 14 *//* 12= -1 , 2 7 12 17 *//* 20= -2 , 4 12 20 32 */#if 1static void InitOPNB_ADPCMATable(void){	int step, nib;	for (step = 0; step <= 48; step++)	{		double stepval = floor(16.0 * pow (11.0 / 10.0, (double)step) * ADPCMA_MIXING_LEVEL);		/* loop over all nibbles and compute the difference */		for (nib = 0; nib < 16; nib++)		{			int value = (int)stepval*((nib&0x07)*2+1)/8;			jedi_table[step*16+nib] = (nib&0x08) ? -value : value;		}	}}#elsestatic int decode_tableA2[49] = {  0x0010, 0x0011, 0x0013, 0x0015, 0x0017, 0x0019, 0x001c, 0x001f,  0x0022, 0x0025, 0x0029, 0x002d, 0x0032, 0x0037, 0x003c, 0x0042,  0x0049, 0x0050, 0x0058, 0x0061, 0x006b, 0x0076, 0x0082, 0x008f,  0x009d, 0x00ad, 0x00be, 0x00d1, 0x00e6, 0x00fd, 0x0117, 0x0133,  0x0151, 0x0173, 0x0198, 0x01c1, 0x01ee, 0x0220, 0x0256, 0x0292,  0x02d4, 0x031c, 0x036c, 0x03c3, 0x0424, 0x048e, 0x0502, 0x0583,  0x0610};static void InitOPNB_ADPCMATable(void){   int ta,tb,tc;   for(ta=0;ta<49;ta++){     for(tb=0;tb<16;tb++){       tc=0;       if(tb&0x04){tc+=((decode_tableA2[ta]*ADPCMA_MIXING_LEVEL));}       if(tb&0x02){tc+=((decode_tableA2[ta]*ADPCMA_MIXING_LEVEL)>>1);}       if(tb&0x01){tc+=((decode_tableA2[ta]*ADPCMA_MIXING_LEVEL)>>2);}       tc+=((decode_tableA2[ta]*ADPCMA_MIXING_LEVEL)>>3);       if(tb&0x08){tc=(0-tc);}       jedi_table[ta*16+tb]=tc;     }   }}#endif/**** ADPCM A (Non control type) ****/INLINE void OPNB_ADPCM_CALC_CHA( YM2610 *F2610, ADPCM_CH *ch ){	UINT32 step;	int data;	ch->now_step += ch->step;	if ( ch->now_step >= (1<<ADPCM_SHIFT) )	{		step = ch->now_step >> ADPCM_SHIFT;		ch->now_step &= (1<<ADPCM_SHIFT)-1;		/* end check */		if ( (ch->now_addr+step) > (ch->end<<1) ) {			ch->flag = 0;			F2610->adpcm_arrivedEndAddress |= ch->flagMask;			return;		}		do{#if 0			if ( ch->now_addr > (pcmsizeA<<1) ) {				LOG(LOG_WAR,("YM2610: Attempting to play past adpcm rom size!\n" ));				return;			}#endif			if( ch->now_addr&1 ) data = ch->now_data & 0x0f;			else			{				ch->now_data = *(pcmbufA+(ch->now_addr>>1));				data = (ch->now_data >> 4)&0x0f;			}			ch->now_addr++;			ch->adpcmx += jedi_table[ch->adpcmd+data];			Limit( ch->adpcmx,ADPCMA_DECODE_MAX, ADPCMA_DECODE_MIN );			ch->adpcmd += decode_tableA1[data];			Limit( ch->adpcmd, 48*16, 0*16 );			/**** calc pcm * volume data ****/			ch->adpcml = ch->adpcmx * ch->volume;		}while(--step);	}	/* output for work of output channels (out_ch[OPNxxxx])*/	*(ch->pan) += ch->adpcml;}/* ADPCM type A */static void FM_ADPCMAWrite(YM2610 *F2610,int r,int v){	ADPCM_CH *adpcm = F2610->adpcm;	UINT8 c = r&0x07;	F2610->adpcmreg[r] = v&0xff; /* stock data */	switch( r ){	case 0x00: /* DM,--,C5,C4,C3,C2,C1,C0 */		/* F2610->port1state = v&0xff; */		if( !(v&0x80) ){			/* KEY ON */			for( c = 0; c < 6; c++ ){				if( (1<<c)&v ){					/**** start adpcm ****/					adpcm[c].step     = (UINT32)((float)(1<<ADPCM_SHIFT)*((float)F2610->OPN.ST.freqbase)/3.0);					adpcm[c].now_addr = adpcm[c].start<<1;					adpcm[c].now_step = (1<<ADPCM_SHIFT)-adpcm[c].step;					/*adpcm[c].adpcmm   = 0;*/					adpcm[c].adpcmx   = 0;					adpcm[c].adpcmd   = 0;					adpcm[c].adpcml   = 0;					adpcm[c].flag     = 1;					if(F2610->pcmbuf==NULL){			/* Check ROM Mapped *//* 						LOG(LOG_WAR,("YM2610: ADPCM-A rom not mapped\n")); */						adpcm[c].flag = 0;					} else{						if(adpcm[c].end >= F2610->pcm_size){		/* Check End in Range *//* 							LOG(LOG_WAR,("YM2610: ADPCM-A end out of range: $%08x\n",adpcm[c].end)); */							adpcm[c].end = F2610->pcm_size-1;						}						if(adpcm[c].start >= F2610->pcm_size)						{	/* Check Start in Range *//* 							LOG(LOG_WAR,("YM2610: ADPCM-A start out of range: $%08x\n",adpcm[c].start)); */							adpcm[c].flag = 0;						}/*LOG(LOG_WAR,("YM2610: Start %06X : %02X %02X %02X\n",adpcm[c].start,pcmbufA[adpcm[c].start],pcmbufA[adpcm[c].start+1],pcmbufA[adpcm[c].start+2]));*/					}				}	/*** (1<<c)&v ***/			}	/**** for loop ****/		} else{			/* KEY OFF */			for( c = 0; c < 6; c++ ){				if( (1<<c)&v )  adpcm[c].flag = 0;			}		}		break;	case 0x01:	/* B0-5 = TL 0.75dB step */		F2610->adpcmTL = &(TL_TABLE[((v&0x3f)^0x3f)*(int)(0.75/EG_STEP)]);		for( c = 0; c < 6; c++ )		{			adpcm[c].volume = F2610->adpcmTL[adpcm[c].IL*(int)(0.75/EG_STEP)] / ADPCMA_DECODE_RANGE / ADPCMA_VOLUME_DIV;			/**** calc pcm * volume data ****/			adpcm[c].adpcml = adpcm[c].adpcmx * adpcm[c].volume;		}		break;	default:		c = r&0x07;		if( c >= 0x06 ) return;		switch( r&0x38 ){		case 0x08:	/* B7=L,B6=R,B4-0=IL */			adpcm[c].IL = (v&0x1f)^0x1f;			adpcm[c].volume = F2610->adpcmTL[adpcm[c].IL*(int)(0.75/EG_STEP)] / ADPCMA_DECODE_RANGE / ADPCMA_VOLUME_DIV;			adpcm[c].pan    = &out_ch[(v>>6)&0x03];			/**** calc pcm * volume data ****/			adpcm[c].adpcml = adpcm[c].adpcmx * adpcm[c].volume;			break;		case 0x10:		case 0x18:			adpcm[c].start  = ( (F2610->adpcmreg[0x18 + c]*0x0100 | F2610->adpcmreg[0x10 + c]) << ADPCMA_ADDRESS_SHIFT);			break;		case 0x20:		case 0x28:			adpcm[c].end    = ( (F2610->adpcmreg[0x28 + c]*0x0100 | F2610->adpcmreg[0x20 + c]) << ADPCMA_ADDRESS_SHIFT);			adpcm[c].end   += (1<<ADPCMA_ADDRESS_SHIFT) - 1;			break;		}	}}#endif /* BUILD_FM_ADPCMA */#if BUILD_YM2608/*******************************************************************************//*		YM2608 local section                                                   *//*******************************************************************************/static YM2608 *FM2608=NULL;	/* array of YM2608's */static int YM2608NumChips;	/* total chip *//* YM2608 Rhythm Number */#define RY_BD  0#define RY_SD  1#define RY_TOP 2#define RY_HH  3#define RY_TOM 4#define RY_RIM 5#if 0/* Get next pcm data */INLINE int YM2608ReadADPCM(int n){	YM2608 *F2608 = &(FM2608[n]);	if( F2608->ADMode & 0x20 )	{	/* buffer memory */		/* F2203->OPN.ST.status |= 0x04; */		return 0;	}	else	{	/* from PCM data register */		FM_STATUS_SET(F2608->OPN.ST,0x08); /* BRDY = 1 */		return F2608->ADData;	}}/* Put decoded data */INLINE void YM2608WriteADPCM(int n,int v){	YM2608 *F2608 = &(FM2608[n]);	if( F2608->ADMode & 0x20 )	{	/* for buffer */		return;	}	else	{	/* for PCM data port */		F2608->ADData = v;		FM_STATUS_SET(F2608->OPN.ST,0x08) /* BRDY = 1 */	}}#endif/* ---------- IRQ flag Controll Write 0x110 ---------- */INLINE void YM2608IRQFlagWrite(FM_ST *ST,int n,int v){	if( v & 0x80 )	{	/* Reset IRQ flag */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -