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

📄 s_fmopl.c

📁 一款游戏机的模拟器
💻 C
📖 第 1 页 / 共 2 页
字号:
		else          SLOT->Cnt += SLOT->Incr;		/* connectoion */		outd += OP_OUT(SLOT,env_out, feedback2);	}}/* ----------- initialize time tabls ----------- */static void init_timetables( FM_OPL *OPL , int ARRATE , int DRRATE ){	int i;	double rate;	/* make attack rate & decay rate tables */	for (i = 0;i < 4;i++) OPL->AR_TABLE[i] = OPL->DR_TABLE[i] = 0;	for (i = 4;i <= 60;i++){		rate  = OPL->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);		OPL->AR_TABLE[i] = (s32)(rate / ARRATE);		OPL->DR_TABLE[i] = (s32)(rate / DRRATE);	}	for (i = 60;i < 76;i++)	{		OPL->AR_TABLE[i] = EG_AED-1;		OPL->DR_TABLE[i] = OPL->DR_TABLE[60];	}}/* ---------- generic table initialize ---------- */static int OPLOpenTable( void ){	int s,t;	double rate;	int i,j;	double pom;	/* allocate dynamic tables */	if( (TL_TABLE = malloc(TL_MAX*2*sizeof(s32))) == NULL)		return 0;	if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(s32 *))) == NULL)	{		free(TL_TABLE);		return 0;	}	if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(s32))) == NULL)	{		free(TL_TABLE);		free(SIN_TABLE);		return 0;	}	if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(s32))) == NULL)	{		free(TL_TABLE);		free(SIN_TABLE);		free(AMS_TABLE);		return 0;	}	/* make total level table */	for (t = 0;t < EG_ENT-1 ;t++){		rate = ((1<<TL_BITS)-1)/pow(10,EG_STEP*t/20);	/* dB -> voltage */		TL_TABLE[       t] =  (int)rate;		TL_TABLE[TL_MAX+t] = -TL_TABLE[t];	}	/* fill volume off area */	for ( t = EG_ENT-1; t < TL_MAX ;t++){		TL_TABLE[t] = TL_TABLE[TL_MAX+t] = 0;	}	/* make sinwave table (total level offet) */	/* degree 0 = degree 180                   = off */	SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2]         = &TL_TABLE[EG_ENT-1];	for (s = 1;s <= SIN_ENT/4;s++){		pom = sin(2*PI*s/SIN_ENT); /* sin     */		pom = 20*log10(1/pom);	   /* decibel */		j = (int)(pom / EG_STEP);         /* TL_TABLE steps */        /* 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];	}	for (s = 0;s < SIN_ENT;s++)	{		SIN_TABLE[SIN_ENT*1+s] = s<(SIN_ENT/2) ? SIN_TABLE[s] : &TL_TABLE[EG_ENT];		SIN_TABLE[SIN_ENT*2+s] = SIN_TABLE[s % (SIN_ENT/2)];		SIN_TABLE[SIN_ENT*3+s] = (s/(SIN_ENT/4))&1 ? &TL_TABLE[EG_ENT] : SIN_TABLE[SIN_ENT*2+s];	}	/* envelope counter -> envelope output table */	for (i=0; i<EG_ENT; i++)	{		/* ATTACK curve */		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;	}	/* off */	ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1;	/* make LFO ams table */	for (i=0; i<AMS_ENT; i++)	{		pom = (1.0+sin(2*PI*i/AMS_ENT))/2; /* sin */		AMS_TABLE[i]         = (s32)((1.0/EG_STEP)*pom); /* 1dB   */		AMS_TABLE[AMS_ENT+i] = (s32)((4.8/EG_STEP)*pom); /* 4.8dB */	}	/* make LFO vibrate table */	for (i=0; i<VIB_ENT; i++)	{		/* 100cent = 1seminote = 6% ?? */		pom = (double)VIB_RATE*0.06*sin(2*PI*i/VIB_ENT); /* +-100sect step */		VIB_TABLE[i]         = (s32)(VIB_RATE + (pom*0.07)); /* +- 7cent */		VIB_TABLE[VIB_ENT+i] = (s32)(VIB_RATE + (pom*0.14)); /* +-14cent */	}	return 1;}static void OPLCloseTable( void ){	free(TL_TABLE);	free(SIN_TABLE);	free(AMS_TABLE);	free(VIB_TABLE);}/* CSM Key Controll */INLINE void CSMKeyControll(OPL_CH *CH){	OPL_SLOT *slot1 = &CH->SLOT[SLOT1];	OPL_SLOT *slot2 = &CH->SLOT[SLOT2];	/* all key off */	OPL_KEYOFF(slot1);	OPL_KEYOFF(slot2);	/* total level latch */	slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl);	slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl);	/* key on */	CH->op1_out[0] = CH->op1_out[1] = 0;	OPL_KEYON(slot1);	OPL_KEYON(slot2);}/* ---------- opl initialize ---------- */static void OPL_initalize(FM_OPL *OPL){	int fn;	/* frequency base */	OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / OPL->rate) / 72  : 0;	/* make time tables */	init_timetables( OPL , OPL_ARRATE , OPL_DRRATE );	/* make fnumber -> increment counter table */	for( fn=0 ; fn < 1024 ; fn++ )	{		OPL->FN_TABLE[fn] = (u32)(OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2);	}	/* LFO freq.table */	OPL->amsIncr = (u32)(OPL->rate ? (double)AMS_ENT*(1<<AMS_SHIFT) / OPL->rate * 3.7 * ((double)OPL->clock/3600000) : 0);	OPL->vibIncr = (u32)(OPL->rate ? (double)VIB_ENT*(1<<VIB_SHIFT) / OPL->rate * 6.4 * ((double)OPL->clock/3600000) : 0);}/* ---------- write a OPL registers ---------- */static void OPLWriteReg(FM_OPL *OPL, int r, int v){	OPL_CH *CH;	int slot;	int block_fnum;	switch(r&0xe0)	{	case 0x00: /* 00-1f:controll */		switch(r&0x1f)		{		case 0x01:			OPL->wavesel = v&0x20;			if(!OPL->wavesel)			{				/* preset compatible mode */				int c;				for(c=0;c<OPL->max_ch;c++)				{					OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];					OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];				}			}			return;
		}		break;	case 0x20:	/* am,vib,ksr,eg type,mul */		slot = slot_array[r&0x1f];		if(slot == -1) return;		set_mul(OPL,slot,v);		return;	case 0x40:		slot = slot_array[r&0x1f];		if(slot == -1) return;		set_ksl_tl(OPL,slot,v);		return;	case 0x60:		slot = slot_array[r&0x1f];		if(slot == -1) return;		set_ar_dr(OPL,slot,v);		return;	case 0x80:		slot = slot_array[r&0x1f];		if(slot == -1) return;		set_sl_rr(OPL,slot,v);		return;	case 0xa0:		switch(r)		{		case 0xbd:			/* amsep,vibdep,r,bd,sd,tom,tc,hh */			{			OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0];			OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0];			OPL->rythm  = v&0x3f;
			}			return;		}		/* keyon,block,fnum */		if( (r&0x0f) > 8) return;		CH = &OPL->P_CH[r&0x0f];		if(!(r&0x10))		{	/* a0-a8 */			block_fnum  = (CH->block_fnum&0x1f00) | v;		}		else		{	/* b0-b8 */			int keyon = (v>>5)&1;			block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff);			if(CH->keyon != keyon)			{				if( (CH->keyon=keyon) )				{					CH->op1_out[0] = CH->op1_out[1] = 0;					OPL_KEYON(&CH->SLOT[SLOT1]);					OPL_KEYON(&CH->SLOT[SLOT2]);				}				else				{					OPL_KEYOFF(&CH->SLOT[SLOT1]);					OPL_KEYOFF(&CH->SLOT[SLOT2]);				}			}		}		/* update */		if((unsigned)CH->block_fnum != (unsigned)block_fnum)		{			int blockRv = 7-(block_fnum>>10);			int fnum   = block_fnum&0x3ff;			CH->block_fnum = block_fnum;			CH->ksl_base = KSL_TABLE[block_fnum>>6];			CH->fc = OPL->FN_TABLE[fnum]>>blockRv;			CH->kcode = (u8)(CH->block_fnum>>9);			if( (OPL->mode&0x40) && CH->block_fnum&0x100) CH->kcode |=1;			CALC_FCSLOT(CH,&CH->SLOT[SLOT1]);			CALC_FCSLOT(CH,&CH->SLOT[SLOT2]);		}		return;	case 0xc0:		/* FB,C */		if( (r&0x0f) > 8) return;		CH = &OPL->P_CH[r&0x0f];		{		int feedback = (v>>1)&7;		CH->FB   = feedback ? (8+1) - feedback : 0;		CH->CON = v&1;		set_algorythm(CH);		}		return;	case 0xe0: /* wave type */		slot = slot_array[r&0x1f];		if(slot == -1) return;		CH = &OPL->P_CH[slot/2];		if(OPL->wavesel)		{			CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v&0x03)*SIN_ENT];		}		return;	}}/* lock/unlock for common table */static int OPL_LockTable(void){	num_lock++;	if(num_lock>1) return 0;	/* first time */	cur_chip = NULL;	/* allocate total level table (128kb space) */	if( !OPLOpenTable() )	{		num_lock--;		return -1;	}	return 0;}static void OPL_UnLockTable(void){	if(num_lock) num_lock--;	if(num_lock) return;	/* last time */	cur_chip = NULL;	OPLCloseTable();}/*******************************************************************************//*		YM3812 local section                                                   *//*******************************************************************************//* ---------- update one of chip ----------- */void YM3812UpdateOne(FM_OPL *OPL, s16 *buffer, int length){	int i;	s16 *buf = buffer;	u32 amsCnt  = OPL->amsCnt;	u32 vibCnt  = OPL->vibCnt;	OPL_CH *CH,*R_CH;	if( (void *)OPL != cur_chip ){		cur_chip = (void *)OPL;		/* channel pointers */		S_CH = OPL->P_CH;		E_CH = &S_CH[6];		/* LFO state */		amsIncr = OPL->amsIncr;		vibIncr = OPL->vibIncr;		ams_table = OPL->ams_table;		vib_table = OPL->vib_table;	}	R_CH = E_CH;    for( i=0; i < length ; i++ )	{		/*            channel A         channel B         channel C      */		/* LFO */		ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];		vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];		outd = 0;		/* FM part */		for(CH=S_CH ; CH < R_CH ; CH++)			OPL_CALC_CH(CH);		/* store to sound buffer */		buf[i] += (s16)((outd >> OPL_OUTSB) / 56);	}	OPL->amsCnt = amsCnt;	OPL->vibCnt = vibCnt;}/* ---------- reset one of chip ---------- */void OPLResetChip(FM_OPL *OPL){	int c,s;	int i;	/* reset chip */	OPL->mode   = 0;	/* normal mode */	OPL_STATUS_RESET(OPL,0x7f);	/* reset with register write */	OPLWriteReg(OPL,0x01,0); /* wabesel disable */	for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0);	/* reset OPerator paramater */	for( c = 0 ; c < OPL->max_ch ; c++ )	{		OPL_CH *CH = &OPL->P_CH[c];		/* OPL->P_CH[c].PAN = OPN_CENTER; */		for(s = 0 ; s < 2 ; s++ )		{			/* wave table */			CH->SLOT[s].wavetable = &SIN_TABLE[0];			/* CH->SLOT[s].evm = ENV_MOD_RR; */			CH->SLOT[s].evc = EG_OFF;			CH->SLOT[s].eve = EG_OFF+1;			CH->SLOT[s].evs = 0;		}	}}/* ----------  Create one of vietual YM3812 ----------       *//* 'rate'  is sampling rate and 'bufsiz' is the size of the  */FM_OPL *OPLCreate(int clock, int rate){	char *ptr;	FM_OPL *OPL;	int state_size;	int max_ch = 9; /* normaly 9 channels */	if( OPL_LockTable() ==-1) return NULL;	/* allocate OPL state space */	state_size  = sizeof(FM_OPL);	state_size += sizeof(OPL_CH)*max_ch;
	/* allocate memory block */	ptr = malloc(state_size);	if(ptr==NULL) return NULL;	/* clear */	memset(ptr,0,state_size);	OPL        = (FM_OPL *)ptr; ptr+=sizeof(FM_OPL);	OPL->P_CH  = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch;
	/* set channel state pointer */	OPL->clock = clock;	OPL->rate  = rate;	OPL->max_ch = max_ch;	/* init grobal tables */	OPL_initalize(OPL);	/* reset chip */	OPLResetChip(OPL);	return OPL;}/* ----------  Destroy one of vietual YM3812 ----------       */void OPLDestroy(FM_OPL *OPL){	OPL_UnLockTable();	free(OPL);}/* ---------- YM3812 I/O interface ---------- */int OPLWrite(FM_OPL *OPL,int a,int v){	if( !(a&1) )	{	/* address port */		OPL->address = v & 0xff;	}	else	{	/* data port */		if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);		OPLWriteReg(OPL,OPL->address,v);	}	return OPL->status>>7;}

⌨️ 快捷键说明

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