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

📄 ym2151.c

📁 十七种模拟器源代码 非常有用的作课程设计不可缺少的
💻 C
📖 第 1 页 / 共 4 页
字号:
		pom = ( (PSG->freq[ kc_channel + op->DT2 ] + op->DT1v) * op->MUL ) >> 1;		op->phase += (pom - op->freq);		op+=8;		pom = ( (PSG->freq[ kc_channel + op->DT2 ] + op->DT1v) * op->MUL ) >> 1;		op->phase += (pom - op->freq);	}}INLINE signed int op_calc(OscilRec * OP, unsigned int env, signed int pm){	unsigned int p;	p = (env<<3) + sin_tab[ ( ((signed int)((OP->phase & ~FREQ_MASK) + (pm<<15))) >> FREQ_SH ) & SIN_MASK ];	if (p >= TL_TAB_LEN)		return 0;	return TL_TAB[p];}INLINE signed int op_calc1(OscilRec * OP, unsigned int env, signed int pm){	unsigned int p;	signed int i;	i = (OP->phase & ~FREQ_MASK) + pm;/*logerror("i=%08x (i>>16)&511=%8i phase=%i [pm=%08x] ",i, (i>>16)&511, OP->phase>>FREQ_SH, pm);*/	p = (env<<3) + sin_tab[ (i>>FREQ_SH) & SIN_MASK];/*logerror("(p&255=%i p>>8=%i) out= %i\n", p&255,p>>8, TL_TAB[p&255]>>(p>>8) );*/	if (p >= TL_TAB_LEN)		return 0;	return TL_TAB[p];}#define volume_calc(OP) (OP->TL + (((unsigned int)OP->volume)>>ENV_SH) + (AM & OP->AMSmask))INLINE void chan_calc(unsigned int chan){OscilRec *OP;unsigned int env;unsigned int AM;	chanout[chan]= c1 = m2 = c2 = 0;	AM = 0;	OP = &PSG->Oscils[chan]; /*M1*/	if (OP->AMS)		AM = PSG->LFA << (OP->AMS-1);	if (OP->PMS)		calc_lfo_pm(OP);	env = volume_calc(OP);	{		signed int out;		out = OP->FB0 + OP->FB;		OP->FB0 = OP->FB;		if (!OP->connect)			/* algorithm 5 */			c1 = m2 = c2 = OP->FB0;		else			/* other algorithms */			*OP->connect = OP->FB0;		OP->FB = 0;		if (env < ENV_QUIET)			OP->FB = op_calc1(OP, env, (out<<OP->FeedBack) );	}	OP += 16; /*C1*/	env = volume_calc(OP);	if (env < ENV_QUIET)		*OP->connect += op_calc(OP, env, c1);	OP -= 8;  /*M2*/	env = volume_calc(OP);	if (env < ENV_QUIET)		*OP->connect += op_calc(OP, env, m2);	OP += 16; /*C2*/	env = volume_calc(OP);	if (env < ENV_QUIET)		chanout[chan] += op_calc(OP, env, c2);}INLINE void chan7_calc(void){OscilRec *OP;unsigned int env;unsigned int AM;	chanout[7]= c1 = m2 = c2 = 0;	AM = 0;	OP = &PSG->Oscils[7]; /*M1*/	if (OP->AMS)		AM = PSG->LFA << (OP->AMS-1);	if (OP->PMS)		calc_lfo_pm(OP);	env = volume_calc(OP);	{		signed int out;		out = OP->FB0 + OP->FB;		OP->FB0 = OP->FB;		if (!OP->connect)			/* algorithm 5 */			c1 = m2 = c2 = OP->FB0;		else			/* other algorithms */			*OP->connect = OP->FB0;		OP->FB = 0;		if (env < ENV_QUIET)			OP->FB = op_calc1(OP, env, (out<<OP->FeedBack) );	}	OP += 16; /*C1*/	env = volume_calc(OP);	if (env < ENV_QUIET)		*OP->connect += op_calc(OP, env, c1);	OP -= 8;  /*M2*/	env = volume_calc(OP);	if (env < ENV_QUIET)		*OP->connect += op_calc(OP, env, m2);	OP += 16; /*C2*/	env = volume_calc(OP);	if (PSG->noise & 0x80)	{		unsigned int noiseout;		noiseout = 0;		if (env < 0x3ff)			noiseout = (env ^ 0x3ff) * 2; /*range of the YM2151 noise output is -2044 to 2040*/		chanout[7] += ((PSG->noiseRNG&0x10000) ? noiseout: -1 * (int)noiseout); /*bit 16 -> output*/	}	else	{		if (env < ENV_QUIET)			chanout[7] += op_calc(OP, env, c2);	}}INLINE void advance(void){OscilRec *op;int i;	if (!(PSG->test&2))		PSG->LFOphase += PSG->LFOfrq;	/* The Noise Generator of the YM2151 is 17-bit shift register.	** Input to the bit16 is negated (bit0 XOR bit3) (EXNOR).	** Output of the register is negated (bit0 XOR bit3).	** Simply use bit16 as the noise output.	*/	PSG->noise_p += PSG->noise_f;	i = (PSG->noise_p>>16);		/*number of events (shifts of the shift register)*/	PSG->noise_p &= 0xffff;	while (i)	{		unsigned int j;		j = ( (PSG->noiseRNG ^ (PSG->noiseRNG>>3) ) & 1) ^ 1;		PSG->noiseRNG = (j<<16) | (PSG->noiseRNG>>1);		i--;	}	/* In real it seems that CSM keyon line is ORed with the KO line inside of the chip.	** This causes it to only work when KO is off, ie. 0	** Below is my implementation only.	*/	if (PSG->CSMreq) /*CSM KEYON/KEYOFF seqeunce request*/	{		if (PSG->CSMreq==2)	/*KEYON*/		{			op = &PSG->Oscils[0]; /*CH 0 M1*/			i = 32;			do			{				if (op->key==0) /*_ONLY_ when KEY is OFF (checked)*/				{					op->phase = 0;					op->state = EG_ATT;				}				op++;				i--;			}while (i);			PSG->CSMreq = 1;		}		else					/*KEYOFF*/		{			op = &PSG->Oscils[0]; /*CH 0 M1*/			i = 32;			do			{				if (op->key==0) /*_ONLY_ when KEY is OFF (checked)*/				{					if (op->state>EG_REL)						op->state = EG_REL;				}				op++;				i--;			}while (i);			PSG->CSMreq = 0;		}	}	op = &PSG->Oscils[0]; /*CH0 M1*/	i = 32;	do	{		op->phase += op->freq;		switch(op->state)		{		case EG_ATT:	/*attack phase*/		{			signed int step;			step = op->volume;			op->volume -= op->delta_AR;			step = (step>>ENV_SH) - (((unsigned int)op->volume)>>ENV_SH); /*number of levels passed since last time*/			if (step > 0)			{				signed int tmp_volume;				tmp_volume = op->volume + (step<<ENV_SH); /*adjust by number of levels*/				do				{					tmp_volume = tmp_volume - (1<<ENV_SH) - ((tmp_volume>>4) & ~ENV_MASK);					if (tmp_volume <= MIN_ATT_INDEX)						break;					step--;				}while(step);				op->volume = tmp_volume;			}			if (op->volume <= MIN_ATT_INDEX)			{				if (op->volume < 0)					op->volume = 0; /*this is not quite correct (checked)*/				op->state = EG_DEC;			}		}		break;		case EG_DEC:	/*decay phase*/			if ( (unsigned int)(op->volume += op->delta_D1R) >= op->D1L )			{				op->volume = op->D1L; /*this is not quite correct (checked)*/				op->state = EG_SUS;			}		break;		case EG_SUS:	/*sustain phase*/			if ( (op->volume += op->delta_D2R) > MAX_ATT_INDEX )			{				op->state = EG_OFF;				op->volume = MAX_ATT_INDEX;			}		break;		case EG_REL:	/*release phase*/			if ( (op->volume += op->delta_RR) > MAX_ATT_INDEX )			{				op->state = EG_OFF;				op->volume = MAX_ATT_INDEX;			}		break;		}		op++;		i--;	}while (i);}#if 0INLINE signed int acc_calc(signed int value){	if (value>=0)	{		if (value < 0x0200)			return (value);		if (value < 0x0400)			return (value & 0xfffffffe);		if (value < 0x0800)			return (value & 0xfffffffc);		if (value < 0x1000)			return (value & 0xfffffff8);		if (value < 0x2000)			return (value & 0xfffffff0);		if (value < 0x4000)			return (value & 0xffffffe0);		return (value & 0xffffffc0);	}	/*else value < 0*/	if (value > -0x0200)		return (value);	if (value > -0x0400)		return (value & 0xfffffffe);	if (value > -0x0800)		return (value & 0xfffffffc);	if (value > -0x1000)		return (value & 0xfffffff8);	if (value > -0x2000)		return (value & 0xfffffff0);	if (value > -0x4000)		return (value & 0xffffffe0);	return (value & 0xffffffc0);}#endif/*first macro saves left and right channels to mono file*//*second macro saves left and right channels to stereo file*/#if 0	/*MONO*/	#ifdef SAVE_SEPARATE_CHANNELS	  #define SAVE_SINGLE_CHANNEL(j) \	  {	signed int pom= -(chanout[j] & PSG->PAN[j*2]); \		if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \		fputc((unsigned short)pom&0xff,sample[j]); \		fputc(((unsigned short)pom>>8)&0xff,sample[j]);  }	#else	  #define SAVE_SINGLE_CHANNEL(j)	#endif#else	/*STEREO*/	#ifdef SAVE_SEPARATE_CHANNELS	  #define SAVE_SINGLE_CHANNEL(j) \	  {	signed int pom = -(chanout[j] & PSG->PAN[j*2]); \		if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \		fputc((unsigned short)pom&0xff,sample[j]); \		fputc(((unsigned short)pom>>8)&0xff,sample[j]); \		pom = -(chanout[j] & PSG->PAN[j*2+1]); \		if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \		fputc((unsigned short)pom&0xff,sample[j]); \		fputc(((unsigned short)pom>>8)&0xff,sample[j]); \	  }	#else	  #define SAVE_SINGLE_CHANNEL(j)	#endif#endif/*first macro saves left and right channels to mono file*//*second macro saves left and right channels to stereo file*/#if 1	/*MONO*/	#ifdef SAVE_SAMPLE	  #define SAVE_ALL_CHANNELS \	  {	signed int pom = outr; \		pom >>= FINAL_SH; \		if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \		/*pom = acc_calc(pom);*/ \		/*fprintf(sample[8]," %i\n",pom);*/ \		fputc((unsigned short)pom&0xff,sample[8]); \		fputc(((unsigned short)pom>>8)&0xff,sample[8]); \	  }	#else	  #define SAVE_ALL_CHANNELS	#endif#else	/*STEREO*/	#ifdef SAVE_SAMPLE	  #define SAVE_ALL_CHANNELS \	  {	signed int pom = outl; \		pom >>= FINAL_SH; \		if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \		fputc((unsigned short)pom&0xff,sample[8]); \		fputc(((unsigned short)pom>>8)&0xff,sample[8]); \		pom = outr; \		pom >>= FINAL_SH; \		if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \		fputc((unsigned short)pom&0xff,sample[8]); \		fputc(((unsigned short)pom>>8)&0xff,sample[8]); \	  }	#else	  #define SAVE_ALL_CHANNELS	#endif#endif/*** 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 that should be generated*/void YM2151UpdateOne(int num, INT16 **buffers, int length){	int i;	signed int outl,outr;	SAMP *bufL, *bufR;	bufL = buffers[0];	bufR = buffers[1];	PSG = &YMPSG[num];	#ifdef USE_MAME_TIMERS		/* ASG 980324 - handled by real timers now */	#else	if (PSG->TimB)	{		PSG->TimBVal -= ( length << TIMER_SH );		if (PSG->TimBVal<=0)		{			PSG->TimBVal += PSG->TimerB[ PSG->TimBIndex ];			if ( PSG->IRQenable & 0x08 )			{				int oldstate = PSG->status & 3;				PSG->status |= 2;				if ((!oldstate) && (PSG->irqhandler)) (*PSG->irqhandler)(1);			}		}	}	#endif	for (i=0; i<length; i++)	{		chan_calc(0);		SAVE_SINGLE_CHANNEL(0)		chan_calc(1);		SAVE_SINGLE_CHANNEL(1)		chan_calc(2);		SAVE_SINGLE_CHANNEL(2)		chan_calc(3);		SAVE_SINGLE_CHANNEL(3)		chan_calc(4);		SAVE_SINGLE_CHANNEL(4)		chan_calc(5);		SAVE_SINGLE_CHANNEL(5)		chan_calc(6);		SAVE_SINGLE_CHANNEL(6)		chan7_calc();		SAVE_SINGLE_CHANNEL(7)		SAVE_ALL_CHANNELS		outl = chanout[0] & PSG->PAN[0];		outr = chanout[0] & PSG->PAN[1];		outl += (chanout[1] & PSG->PAN[2]);		outr += (chanout[1] & PSG->PAN[3]);		outl += (chanout[2] & PSG->PAN[4]);		outr += (chanout[2] & PSG->PAN[5]);		outl += (chanout[3] & PSG->PAN[6]);		outr += (chanout[3] & PSG->PAN[7]);		outl += (chanout[4] & PSG->PAN[8]);		outr += (chanout[4] & PSG->PAN[9]);		outl += (chanout[5] & PSG->PAN[10]);		outr += (chanout[5] & PSG->PAN[11]);		outl += (chanout[6] & PSG->PAN[12]);		outr += (chanout[6] & PSG->PAN[13]);		outl += (chanout[7] & PSG->PAN[14]);		outr += (chanout[7] & PSG->PAN[15]);		outl >>= FINAL_SH;		outr >>= FINAL_SH;		if (outl > MAXOUT) outl = MAXOUT;			else if (outl < MINOUT) outl = MINOUT;		if (outr > MAXOUT) outr = MAXOUT;			else if (outr < MINOUT) outr = MINOUT;		((SAMP*)bufL)[i] = (SAMP)outl;		((SAMP*)bufR)[i] = (SAMP)outr;		#ifdef USE_MAME_TIMERS		/* ASG 980324 - handled by real timers now */		#else		/* calculate timer A */		if (PSG->TimA)		{			PSG->TimAVal -= ( 1 << TIMER_SH );			if (PSG->TimAVal <= 0)			{				PSG->TimAVal += PSG->TimerA[ PSG->TimAIndex ];				if (PSG->IRQenable & 0x04)				{					int oldstate = PSG->status & 3;					PSG->status |= 1;					if ((!oldstate) && (PSG->irqhandler)) (*PSG->irqhandler)(1);				}				if (PSG->IRQenable & 0x80)					PSG->CSMreq = 2; /*request KEYON/KEYOFF sequence*/			}		}		#endif		lfo_calc();		advance();	}}void YM2151SetIrqHandler(int n, void(*handler)(int irq)){	YMPSG[n].irqhandler = handler;}void YM2151SetPortWriteHandler(int n, mem_write_handler handler){	YMPSG[n].porthandler = handler;}

⌨️ 快捷键说明

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