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

📄 ym2151.c

📁 这个是延伸mame的在wince平台下的游戏模拟器的代码
💻 C
📖 第 1 页 / 共 3 页
字号:

	/* initialize hardware registers */

	for( i=0; i<32; i++){
		memset(&chip->Oscils[i],'\0',sizeof(OscilRec));
		chip->Oscils[i].volume = VOLUME_OFF;
	}

	for ( i=0; i<8; i++){
		set_connect_feedback_pan(&chip->Oscils[i],0);
	}

	chip->LFOphase = 0;
	chip->LFOfrq = 0;
	chip->PMD = 0;
	chip->AMD = 0;
	chip->LFOwave = 0;
	chip->LFA = 0;
	chip->LFP = 0;

	chip->IRQenable = 0;
#ifdef USE_MAME_TIMERS
	/* ASG 980324 -- reset the timers before writing to the registers */
	chip->TimATimer = 0;
	chip->TimBTimer = 0;
#else
	chip->TimA = 0;
	chip->TimB = 0;
	chip->TimAVal = 0;
	chip->TimBVal = 0;
#endif
	chip->TimAIndex = 0;
	chip->TimBIndex = 0;

	chip->CT = 0;
	chip->noise = 0;

	chip->status = 0;
	chip->need_refresh = 1; /*emulator needs refresh after reset*/
}



void refresh_chip(void)
{
unsigned int kc_index_oscil, kc_index_channel, kc, chan;
unsigned char v;
OscilRec * osc;

    if (PSG->need_refresh==0)
	return;

    PSG->need_refresh = 0;

    for (chan=0; chan<8; chan++)
    {
	osc = &PSG->Oscils[chan];
	kc = osc->KC;
	kc_index_channel = KC_TO_INDEX[kc] + osc->KF;
	kc >>=2;

/*calc freq begin operator 0*/
        kc_index_oscil = kc_index_channel + osc->DT2;  /*DT2 offset*/
	osc->freq = PSG->freq[ kc_index_oscil ] * osc->mul;
	osc->freq += PSG->DT1freq[ osc->DT1 + kc ];    /*DT1 value*/
/*calc freq end*/ /*calc envelopes begin*/
	v = kc >> osc->KS;
	osc->delta_AR  = PSG->A_Time[ osc->AR + v];    /* 2*RR + RKS =max 95*/
	osc->delta_D1R = PSG->D_Time[osc->D1R + v];
	osc->delta_D2R = PSG->D_Time[osc->D2R + v];
	osc->delta_RR =  PSG->D_Time[ osc->RR + v];
/*calc envelopes end*/

	osc+=8;

/*calc freq begin operator 1*/
        kc_index_oscil = kc_index_channel + osc->DT2;  /*DT2 offset*/
	osc->freq = PSG->freq[ kc_index_oscil ] * osc->mul;
	osc->freq += PSG->DT1freq[ osc->DT1 + kc ];    /*DT1 value*/
/*calc freq end*/ /*calc envelopes begin*/
	v = kc >> osc->KS;
	osc->delta_AR  = PSG->A_Time[ osc->AR + v];    /* 2*RR + RKS =max 95*/
	osc->delta_D1R = PSG->D_Time[osc->D1R + v];
	osc->delta_D2R = PSG->D_Time[osc->D2R + v];
	osc->delta_RR =  PSG->D_Time[ osc->RR + v];
/*calc envelopes end*/

	osc+=8;

/*calc freq begin operator 2*/
        kc_index_oscil = kc_index_channel + osc->DT2;  /*DT2 offset*/
	osc->freq = PSG->freq[ kc_index_oscil ] * osc->mul;
	osc->freq += PSG->DT1freq[ osc->DT1 + kc ];    /*DT1 value*/
/*calc freq end*/ /*calc envelopes begin*/
	v = kc >> osc->KS;
	osc->delta_AR  = PSG->A_Time[ osc->AR + v];    /* 2*RR + RKS =max 95*/
	osc->delta_D1R = PSG->D_Time[osc->D1R + v];
	osc->delta_D2R = PSG->D_Time[osc->D2R + v];
	osc->delta_RR =  PSG->D_Time[ osc->RR + v];
/*calc envelopes end*/

	osc+=8;

/*calc freq begin operator 3*/
        kc_index_oscil = kc_index_channel + osc->DT2;  /*DT2 offset*/
	osc->freq = PSG->freq[ kc_index_oscil ] * osc->mul;
	osc->freq += PSG->DT1freq[ osc->DT1 + kc ];    /*DT1 value*/
/*calc freq end*/ /*calc envelopes begin*/
	v = kc >> osc->KS;
	osc->delta_AR  = PSG->A_Time[ osc->AR + v];    /* 2*RR + RKS =max 95*/
	osc->delta_D1R = PSG->D_Time[osc->D1R + v];
	osc->delta_D2R = PSG->D_Time[osc->D2R + v];
	osc->delta_RR =  PSG->D_Time[ osc->RR + v];
/*calc envelopes end*/

    }

}

void lfo_calc(void)
{
signed int phase,pom;

	phase = ( (PSG->LFOphase+=PSG->LFOfrq) >> LFO_SH ) & LFO_MASK;
	switch(PSG->LFOwave){
	case 0:	/*saw ?*/
		if (phase>=(LFO_LEN/2)){
			PSG->LFP = 0;
		}else{
			PSG->LFP = 0;
		}
		phase = PSG->AMD - phase;
		if (phase<0)	PSG->LFA = 0;
		else		PSG->LFA = phase;
		break;
	case 1:	/*square OK*/
		if (phase>=(LFO_LEN/2)){
			PSG->LFA = 0;
			PSG->LFP = -PSG->PMD;
		}else{
			PSG->LFA = PSG->AMD;
			PSG->LFP = PSG->PMD;
		}
		break;
	case 2:	/*triangle ?*/
		pom = phase;
		if (phase>=(LFO_LEN/2)){
			phase = LFO_LEN - ((phase-(LFO_LEN/2))<<1);
			phase = PSG->AMD - phase;
			if (phase<0)	PSG->LFA = 0;
			else		PSG->LFA = phase;
		}else{
			phase = PSG->AMD - (phase<<1);
			if (phase<0)	PSG->LFA = 0;
			else		PSG->LFA = phase;
		}
		if (pom<(LFO_LEN/4)){
			phase = PSG->PMD - pom;
			if (phase>0) phase = PSG->PMD - phase; else phase = PSG->PMD;
		}else{
			phase = PSG->PMD;
		}
		PSG->LFP = 0;
		break;
	case 3:	/*noise  (!!! real implementation is unknown !!!) */
		pom = ( ( (phase & 1)^((phase&4)>>2) ) <<7) | (phase>>1);
		phase = PSG->AMD - pom;
		if (phase<0)	PSG->LFA = 0;
		else		PSG->LFA = phase;
		phase = PSG->PMD - pom;
		if (abs(phase)>abs(PSG->PMD))	PSG->LFP = 0;
		else				PSG->LFP = phase;
		break;
	}
}


void pm_calc(OscilRec *op, int chan)
{
int inde,pom;

	inde = PSG->LFP; /* -127..+127 (8bits signed)*/
	switch( PSG->Oscils[chan].PMS ){
	case 0:	op->LFOpm=0; return; break;
	case 1: inde<<=5; break;
	case 2: inde<<=4; break;
	case 3: inde<<=3; break;
	case 4: inde<<=2; break;
	case 5: inde<<=1; break;
	case 6: inde>>=1; break;
	case 7: inde = (inde/2)+inde+(inde*2); break;
	}
	pom = PSG->freq[ op->KCindex + inde ] * op->mul + op->DT1val;
}


static unsigned int volume_calc(OscilRec *op)
{

	op->phase+=op->freq;

	switch(op->state){
	case EG_ATT:	/*attack phase*/
		if ( (op->attack_volume -= op->delta_AR) < MIN_VOLUME_INDEX ){
			op->volume = MIN_VOLUME_INDEX;
			op->state = EG_DEC;
		}
		else
			op->volume = attack_curve[op->attack_volume>>ENV_SH];
		break;
	case EG_DEC:	/*decay phase*/
		if ( (op->volume += op->delta_D1R) > op->D1L )
			op->state = EG_SUS;
		break;
	case EG_SUS:	/*sustain phase*/
		if ( (op->volume += op->delta_D2R) > MAX_VOLUME_INDEX ){
			op->state = EG_OFF;
			op->volume = VOLUME_OFF;
		}
		break;
	case EG_REL:	/*release phase*/
		if ( (op->volume += op->delta_RR) > MAX_VOLUME_INDEX ){
			op->state = EG_OFF;
			op->volume = VOLUME_OFF;
		}
		break;
	}

	return op->TL + (op->volume>>ENV_SH);
}


#define op_calc(OP,env,pm)  sin_tab[ ( (OP->phase>>FREQ_SH) + pm ) & SIN_MASK] [  env  /*+ (AM & OP->AMSmask)*/ ]

static void chan_calc(unsigned int chan)
{
unsigned int env;
OscilRec *OP;

	chanout = c1 = m2 = c2 = 0;
	OP = &PSG->Oscils[chan]; /*M1*/

	env = volume_calc(OP);
	if (env < ENV_RES)
	{
		signed int out;

		if (OP->FeedBack){
			out = OP->OscilFB;
			OP->OscilFB = op_calc(OP, env, (OP->OscilFB>>OP->FeedBack) );
			out = (OP->OscilFB + out)/2;
		}else{
			out = op_calc(OP, env, 0);
		}
		if( !OP->connect ){
			/* algorithm 5  */
			c1 = m2 = c2 = out;
		}else{
			/* other algorithm */
			*OP->connect += out;
		}
	}

	OP+=16; /*C1*/
	env = volume_calc(OP);
	if( env < ENV_RES )
		*OP->connect += op_calc(OP, env, c1);

	OP-=8;  /*M2*/
	env = volume_calc(OP);
	if( env < ENV_RES )
		*OP->connect += op_calc(OP, env, m2);

	OP+=16; /*C2*/
	env = volume_calc(OP);
	if( env < ENV_RES )
		*OP->connect += op_calc(OP, env, c2);

}

/*
** Generate samples for one of the YM2151's
**
** 'num' is the number of virtual YM2151
** '**buffers' is table of pointers to the buffers: left and right
** 'length' is the number of samples should be generated
*/
void YM2151UpdateOne(int num, SAMP **buffers, int length)
{
    unsigned int i;
    signed int outl,outr;

	bufL = buffers[0];
	bufR = buffers[1];

	PSG = &YMPSG[num];
	refresh_chip();

#ifndef USE_MAME_TIMERS
	/*calculate timers...*/
	if (PSG->TimA){
		PSG->TimAVal -= ( length << TIMER_SH );
		if (PSG->TimAVal<=0){
			PSG->TimA=0;
			/* ASG 980324 - handled by real timers now*/
			if ( PSG->IRQenable & 0x04 ){
				PSG->status |= 1;
				if (PSG->handler) (*PSG->handler)();
			}
		}
	}
	if (PSG->TimB){
		PSG->TimBVal -= ( length << TIMER_SH );
		if (PSG->TimBVal<=0){
			PSG->TimB=0;
			/* ASG 980324 - handled by real timers now*/
			if ( PSG->IRQenable & 0x08 ){
				PSG->status |= 2;
				if (PSG->handler) (*PSG->handler)();
			}
		}
	}
#endif

for (i=0; i<8; i++)
{
  outl=PSG->Oscils[i].PAN;
  mask[i*2] = (outl&0x40) ? 0xffffffff : 0x0;
  mask[i*2+1]=(outl&0x80) ? 0xffffffff : 0x0;
}


for( i = 0; i<length; i++ ){

chan_calc(0);
    outl = chanout & mask[0];
    outr = chanout & mask[1];
chan_calc(1);
    outl += (chanout & mask[2]);
    outr += (chanout & mask[3]);
chan_calc(2);
    outl += (chanout & mask[4]);
    outr += (chanout & mask[5]);
chan_calc(3);
    outl += (chanout & mask[6]);
    outr += (chanout & mask[7]);
chan_calc(4);
    outl += (chanout & mask[8]);
    outr += (chanout & mask[9]);
chan_calc(5);
    outl += (chanout & mask[10]);
    outr += (chanout & mask[11]);
chan_calc(6);
    outl += (chanout & mask[12]);
    outr += (chanout & mask[13]);
chan_calc(7);
    outl += (chanout & mask[14]);
    outr += (chanout & mask[15]);


	if (sample_16bit){ 	/*16 bit mode*/
		outl >>= FINAL_SH16;
		outr >>= FINAL_SH16;
		if (outl > 32767) outl = 32767;
			else if (outl < -32768) outl = -32768;
		if (outr > 32767) outr = 32767;
			else if (outr < -32768) outr = -32768;
		((unsigned short*)bufL)[i] = (unsigned short)outl;
		((unsigned short*)bufR)[i] = (unsigned short)outr;
	}else{			/*8 bit mode*/
		outl >>= FINAL_SH8;
		outr >>= FINAL_SH8;
		if (outl > 127) outl = 127;
			else if (outl < -128) outl = -128;
		if (outr > 127) outr = 127;
			else if (outr < -128) outr = -128;
		((unsigned char*)bufL)[i] = (unsigned char)outl;
		((unsigned char*)bufR)[i] = (unsigned char)outr;
	}

}

}






#if 0
#ifdef SAVE_SEPARATE_CHANNELS
	for (j=7; j>=0; j--)
	{
	    pom1= -(ChanOut[j] & mask[j]);
		if (pom1 > 32767) pom1 = 32767;
			else if (pom1 < -32768) pom1 = -32768;
	    fputc((unsigned short)pom1&0xff,sample[j]);
	    fputc(((unsigned short)pom1>>8)&0xff,sample[j]);
	}
#endif
#endif

void YM2151SetIrqHandler(int n, void(*handler)(void))
{
    YMPSG[n].handler = handler;
}

void YM2151SetPortWriteHandler(int n, void(*handler)(int offset, int data))
{
    YMPSG[n].porthandler = handler;
}

⌨️ 快捷键说明

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