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

📄 fmopl.c

📁 DC的SEGA_GG模拟器源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
			CH->op1_out[1] = CH->op1_out[0];
			*CH->connect1 += CH->op1_out[0] = OP_OUT(SLOT,env_out,feedback1);
		}
		else
		{
			*CH->connect1 += OP_OUT(SLOT,env_out,0);
		}
	}else
	{
		CH->op1_out[1] = CH->op1_out[0];
		CH->op1_out[0] = 0;
	}
	/* SLOT 2 */
	SLOT = &CH->SLOT[SLOT2];
	env_out=OPL_CALC_SLOT(SLOT);
	if( env_out < EG_ENT-1 )
	{
		/* PG */
		if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
		else          SLOT->Cnt += SLOT->Incr;
		/* connectoion */
		outd[0] += OP_OUT(SLOT,env_out, feedback2);
	}
}

/* ---------- calcrate rythm block ---------- */
#define WHITE_NOISE_db 6.0
static __inline void OPL_CALC_RH( OPL_CH *CH )
{
	UINT32 env_tam,env_sd,env_top,env_hh;
	int whitenoise = (int)((rand()&1)*(WHITE_NOISE_db/EG_STEP));
	INT32 tone8;

	OPL_SLOT *SLOT;
	int env_out;

	/* BD : same as FM serial mode and output level is large */
	feedback2 = 0;
	/* SLOT 1 */
	SLOT = &CH[6].SLOT[SLOT1];
	env_out=OPL_CALC_SLOT(SLOT);
	if( env_out < EG_ENT-1 )
	{
		/* PG */
		if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
		else          SLOT->Cnt += SLOT->Incr;
		/* connectoion */
		if(CH[6].FB)
		{
			int feedback1 = (CH[6].op1_out[0]+CH[6].op1_out[1])>>CH[6].FB;
			CH[6].op1_out[1] = CH[6].op1_out[0];
			feedback2 = CH[6].op1_out[0] = OP_OUT(SLOT,env_out,feedback1);
		}
		else
		{
			feedback2 = OP_OUT(SLOT,env_out,0);
		}
	}else
	{
		feedback2 = 0;
		CH[6].op1_out[1] = CH[6].op1_out[0];
		CH[6].op1_out[0] = 0;
	}
	/* SLOT 2 */
	SLOT = &CH[6].SLOT[SLOT2];
	env_out=OPL_CALC_SLOT(SLOT);
	if( env_out < EG_ENT-1 )
	{
		/* PG */
		if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
		else          SLOT->Cnt += SLOT->Incr;
		/* connectoion */
		outd[0] += OP_OUT(SLOT,env_out, feedback2)*2;
	}

	// SD  (17) = mul14[fnum7] + white noise
	// TAM (15) = mul15[fnum8]
	// TOP (18) = fnum6(mul18[fnum8]+whitenoise)
	// HH  (14) = fnum7(mul18[fnum8]+whitenoise) + white noise
	env_sd =OPL_CALC_SLOT(SLOT7_2) + whitenoise;
	env_tam=OPL_CALC_SLOT(SLOT8_1);
	env_top=OPL_CALC_SLOT(SLOT8_2);
	env_hh =OPL_CALC_SLOT(SLOT7_1) + whitenoise;

	/* PG */
	if(SLOT7_1->vib) SLOT7_1->Cnt += (2*SLOT7_1->Incr*vib/VIB_RATE);
	else             SLOT7_1->Cnt += 2*SLOT7_1->Incr;
	if(SLOT7_2->vib) SLOT7_2->Cnt += ((CH[7].fc*8)*vib/VIB_RATE);
	else             SLOT7_2->Cnt += (CH[7].fc*8);
	if(SLOT8_1->vib) SLOT8_1->Cnt += (SLOT8_1->Incr*vib/VIB_RATE);
	else             SLOT8_1->Cnt += SLOT8_1->Incr;
	if(SLOT8_2->vib) SLOT8_2->Cnt += ((CH[8].fc*48)*vib/VIB_RATE);
	else             SLOT8_2->Cnt += (CH[8].fc*48);

	tone8 = OP_OUT(SLOT8_2,whitenoise,0 );

	/* SD */
	if( env_sd < EG_ENT-1 )
		outd[0] += OP_OUT(SLOT7_1,env_sd, 0)*8;
	/* TAM */
	if( env_tam < EG_ENT-1 )
		outd[0] += OP_OUT(SLOT8_1,env_tam, 0)*2;
	/* TOP-CY */
	if( env_top < EG_ENT-1 )
		outd[0] += OP_OUT(SLOT7_2,env_top,tone8)*2;
	/* HH */
	if( env_hh  < EG_ENT-1 )
		outd[0] += OP_OUT(SLOT7_2,env_hh,tone8)*2;
}

/* ----------- 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] = (int)(rate / ARRATE);
		OPL->DR_TABLE[i] = (int)(rate / DRRATE);
	}
	for (i = 60;i < 76;i++)
	{
		OPL->AR_TABLE[i] = EG_AED-1;
		OPL->DR_TABLE[i] = OPL->DR_TABLE[60];
	}
#if 0
	for (i = 0;i < 64 ;i++){	/* make for overflow area */
		Log(LOG_WAR,"rate %2d , ar %f ms , dr %f ms \n",i,
			((double)(EG_ENT<<ENV_BITS) / OPL->AR_TABLE[i]) * (1000.0 / OPL->rate),
			((double)(EG_ENT<<ENV_BITS) / OPL->DR_TABLE[i]) * (1000.0 / OPL->rate) );
	}
#endif
}

/* ---------- 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(INT32))) == NULL)
		return 0;
	if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL)
	{
		free(TL_TABLE);
		return 0;
	}
	if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL)
	{
		free(TL_TABLE);
		free(SIN_TABLE);
		return 0;
	}
	if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == 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];
/*		Log(LOG_INF,"TotalLevel(%3d) = %x\n",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];
/*		Log(LOG_INF,"sin(%3d) = %f:%f db\n",s,pom,(double)j * EG_STEP);*/
	}
	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]         = (int)((1.0/EG_STEP)*pom); /* 1dB   */
		AMS_TABLE[AMS_ENT+i] = (int)((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]         = (int)(VIB_RATE + (pom*0.07)); /* +- 7cent */
		VIB_TABLE[VIB_ENT+i] = (int)(VIB_RATE + (pom*0.14)); /* +-14cent */
		/* Log(LOG_INF,"vib %d=%d\n",i,VIB_TABLE[VIB_ENT+i]); */
	}
	return 1;
}


static void OPLCloseTable( void )
{
	free(TL_TABLE);
	free(SIN_TABLE);
	free(AMS_TABLE);
	free(VIB_TABLE);
}

/* CSM Key Controll */
static __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;
	/* Timer base time */
	OPL->TimerBase = 1.0/((double)OPL->clock / 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] = (unsigned int)(OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2);
	}
	/* LFO freq.table */
	OPL->amsIncr = (int)(OPL->rate ? (double)AMS_ENT*(1<<AMS_SHIFT) / OPL->rate * 3.7 * ((double)OPL->clock/3600000) : 0);
	OPL->vibIncr = (int)(OPL->rate ? (double)VIB_ENT*(1<<VIB_SHIFT) / OPL->rate * 6.4 * ((double)OPL->clock/3600000) : 0);
}

/* ---------- write a OPL registers ---------- */
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:
			/* wave selector enable */
			if(OPL->type&OPL_TYPE_WAVESEL)
			{
				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;
		case 0x02:	/* Timer 1 */
			OPL->T[0] = (256-v)*4;
			break;
		case 0x03:	/* Timer 2 */
			OPL->T[1] = (256-v)*16;
			return;
		case 0x04:	/* IRQ clear / mask and Timer enable */
			if(v&0x80)
			{	/* IRQ flag clear */
				OPL_STATUS_RESET(OPL,0x7f);
			}
			else
			{	/* set IRQ mask ,timer enable*/
				UINT8 st1 = v&1;
				UINT8 st2 = (v>>1)&1;
				/* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */
				OPL_STATUS_RESET(OPL,v&0x78);
				OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01);
				/* timer 2 */
				if(OPL->st[1] != st2)
				{
					double interval = st2 ? (double)OPL->T[1]*OPL->TimerBase : 0.0;
					OPL->st[1] = st2;
					if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval);
				}
				/* timer 1 */
				if(OPL->st[0] != st1)
				{
					double interval = st1 ? (double)OPL->T[0]*OPL->TimerBase : 0.0;
					OPL->st[0] = st1;
					if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval);
				}
			}
			return;
#if BUILD_Y8950
		case 0x06:		/* Key Board OUT */
			if(OPL->type&OPL_TYPE_KEYBOARD)
			{
				if(OPL->keyboardhandler_w)
					OPL->keyboardhandler_w(OPL->keyboard_param,v);
				else
					Log(LOG_WAR,"OPL:write unmapped KEYBOARD port\n");
			}
			return;
		case 0x07:	/* DELTA-T controll : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */
			if(OPL->type&OPL_TYPE_ADPCM)
				YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
			return;
		case 0x08:	/* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */
			OPL->mode = v;
			v&=0x1f;	/* for DELTA-T unit */
		case 0x09:		/* START ADD */
		case 0x0a:
		case 0x0b:		/* STOP ADD  */
		case 0x0c:
		case 0x0d:		/* PRESCALE   */
		case 0x0e:
		case 0x0f:		/* ADPCM data */
		case 0x10: 		/* DELTA-N    */
		case 0x11: 		/* DELTA-N    */
		case 0x12: 		/* EG-CTRL    */
			if(OPL->type&OPL_TYPE_ADPCM)
				YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
			return;
#if 0
		case 0x15:		/* DAC data    */
		case 0x16:
		case 0x17:		/* SHIFT    */
			return;
		case 0x18:		/* I/O CTRL (Direction) */
			if(OPL->type&OPL_TYPE_IO)
				OPL->portDirection = v&0x0f;
			return;
		case 0x19:		/* I/O DATA */
			if(OPL->type&OPL_TYPE_IO)
			{
				OPL->portLatch = v;
				if(OPL->porthandler_w)
					OPL->porthandler_w(OPL->port_param,v&OPL->portDirection);
			}
			return;
		case 0x1a:		/* PCM data */
			return;
#endif
#endif
		}
		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 */
			{
			UINT8 rkey = OPL->rythm^v;
			OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0];
			OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0];
			OPL->rythm  = v&0x3f;
			if(OPL->rythm&0x20)
			{
#if 0
				usrintf_showmessage("OPL Rythm mode select");
#endif
				/* BD key on/off */
				if(rkey&0x10)
				{
					if(v&0x10)
					{
						OPL->P_CH[6].op1_out[0] = OPL->P_CH[6].op1_out[1] = 0;
						OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT1]);
						OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT2]);

⌨️ 快捷键说明

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