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

📄 fm.c

📁 这个是延伸mame的在wince平台下的游戏模拟器的代码
💻 C
📖 第 1 页 / 共 5 页
字号:
			CALC_FCSLOT(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] );
			CALC_FCSLOT(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] );
			CALC_FCSLOT(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode );
		}
	}else CALC_FCOUNT( cch[2] );

    for( i=0; i < length ; i++ )
	{
		/*            channel A         channel B         channel C      */
		outd[OPN_CENTER] = 0;
		/* calcrate FM */
		for( ch=0;ch<3;ch++) FM_CALC_CH( cch[ch] );
		/* limit check */
		data = Limit( outd[OPN_CENTER] , OPN_MAXOUT, OPN_MINOUT );
		/* store to sound buffer */
#ifndef FM_OUTPUT_PROC
		if( sample_16bit ) ((unsigned short *)buf)[i] = data >> OPN_OUTSB;
		else           ((unsigned char  *)buf)[i]     = data >> OPN_OUTSB_8;
#else
		outputproc( (void **)&buf, data );
#endif

#ifdef INTERNAL_TIMER
		/* timer controll */
		CALC_TIMER_A( num, State , cch[2] );
#endif
	}
#ifdef INTERNAL_TIMER
	CALC_TIMER_B( num, State , length );
#endif
}

/* ---------- 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->index);
	/* status clear */
	OPN->ST.irqmask = 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);
}
#if 0
/* ---------- return the buffer ---------- */
FMSAMPLE *YM2203Buffer(int n)
{
    return FM2203[n].Buf;
}

/* ---------- set buffer ---------- */
int YM2203SetBuffer(int n, FMSAMPLE *buf)
{
	if( buf == 0 ) return -1;
    FM2203[n].Buf = buf;
	return 0;
}
#endif

/* ----------  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,  int bitsize ,
               FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler)
{
	int i;

	if (FM2203) return (-1);	/* duplicate init. */

	FMNumChips = num;
	if( bitsize == 16 ) sample_16bit = 1;
	else                sample_16bit = 0;

	/* allocate ym2203 state space */
	if( (FM2203 = (YM2203 *)malloc(sizeof(YM2203) * FMNumChips))==NULL)
		return (-1);
	/* clear */
	memset(FM2203,0,sizeof(YM2203) * FMNumChips);
	/* allocate total level table (128kb space) */
	if( !FMInitTable() )
	{
		free( FM2203 );
		return (-1);
	}

	for ( i = 0 ; i < FMNumChips; i++ ) {
		FM2203[i].OPN.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;
		/* Extend handler */
		FM2203[i].OPN.ST.Timer_Handler = TimerHandler;
		FM2203[i].OPN.ST.IRQ_Handler   = IRQHandler;
		YM2203ResetChip(i);
	}
#ifdef FM_OUTPUT_PROC
	if( sample_16bit ){
	  outputproc = (void (*)( void **, int ))bufout16;
	} else{
	  outputproc = (void (*)( void **, int ))bufout8;
	}
#endif
	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,int 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;
}

unsigned char 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( n,&(F2203->OPN.ST) );
	}
	else
	{	/* Timer A */
		YM2203UpdateReq(n);
		/* timer update */
		TimerAOver( n,&(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 */





#ifdef BUILD_YM2608
/*******************************************************************************/
/*		YM2608 local section                                                   */
/*******************************************************************************/
static YM2608 *FM2608=NULL;	/* array of YM2608's */

/* 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 */
		F2608->OPN.ST.status |= 0x08;	/* BRDY = 1 */
		if( !F2608->OPN.ST.irq && (F2608->OPN.ST.status & F2608->OPN.ST.irqmask) )
		{
			F2608->OPN.ST.irq = 1;
			/* callback user interrupt handler */
			if(EXIRQHandler) EXIRQHandler(n,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;
		F2608->OPN.ST.status |= 0x08;	/* BRDY = 1 */
		if( !F2608->OPN.ST.irq && (F2608->OPN.ST.status & F2608->OPN.ST.irqmask) )
		{
			F2608->OPN.ST.irq = 1;
			/* callback user interrupt handler */
			if(EXIRQHandler) EXIRQHandler(n,1);
		}
	}
}

/* ---------- ADPCM Register Write 0x100-0x10f ---------- */
INLINE void YM2608ADPCMWrite(int n,int r,int v)
{
	YM2608 *F2608 = &(FM2608[n]);

	switch(r)
	{
	case 0x00:
		{
		/* START,REC,MEMDATA,REPEAT,SPOFF,--,--,RESET */
		int cng = F2608->ADMode ^ v;
		F2608->ADMode = v;
		switch( v & 0xe0 )
		{
		case 0x80:	/* ADPCM play from PCM data port after write PCM data */
			break;
		case 0xa0:	/* ADPCM play from buffer memory */
			break;
		case 0x60:	/* write buffer MEMORY from PCM data port */
			break;
		case 0x20:	/* read  buffer MEMORY to   PCM data port */
			break;
		}
		}
		break;
	case 0x01:
		/* L,R,-,-,SAMPLE,DA/AD,RAMTYPE,ROM */
		F2608->ADPAN = v>>6;
		break;
	case 0x02:	/* Start Address L */
		F2608->ADStart = (F2608->ADStart & 0xff00) | v;
		break;
	case 0x03:	/* Start Address H */
		F2608->ADStart = (F2608->ADStart & 0x00ff) | (v<<8);
		break;
	case 0x04:	/* Stop Address L */
		F2608->ADStop = (F2608->ADStop & 0xff00) | v;
		break;
	case 0x05:	/* Stop Address H */
		F2608->ADStop = (F2608->ADStop & 0x00ff) | (v<<8);
		break;
	case 0x06:	/* Prescale L (PCM and Recoard frq) */
	case 0x07:	/* Proscale H */
		break;
	case 0x08:	/* ADPCM data */
		break;
	case 0x09:	/* DELTA-N L (ADPCM Playback Prescaler) */
		F2608->ADDelta = (F2608->ADDelta & 0xff00) | v;
		break;
	case 0x0a:	/* DELTA-N H */
		F2608->ADDelta = (F2608->ADDelta & 0x00ff) | (v<<8);
		break;
	case 0x0b:	/* Level control (volume) */
		F2608->ADTL = v;
		break;
	case 0x0c:	/* Limit address L */
		F2608->ADLimit = (F2608->ADLimit & 0xff00) | v;
		break;
	case 0x0d:	/* Limit address H */
		F2608->ADLimit = (F2608->ADLimit & 0x00ff) | (v<<8);
		break;
	case 0x0e:	/* DAC data */
		break;
	case 0x0f:	/* PCM data port */
		F2608->ADData = v;
		F2608->OPN.ST.status &= ~0x08;
		if( F2608->OPN.ST.irq && !(F2608->OPN.ST.status & F2608->OPN.ST.irqmask) )
		{
			F2608->OPN.ST.irq = 0;
			/* callback user interrupt handler */
			if(EXIRQHandler) EXIRQHandler(n,0);
		}
		break;
	}
}

/* ---------- Rhythm Register Write 0x10-0x1f ---------- */
INLINE void YM2608RhythmWrite(int n,int r,int v)
{
	YM2608 *F2608 = &(FM2608[n]);
	int c;

	switch( r ){
	case 0x10: /* DM,--,RIM,TOM,HH,TOP,SD,BD */
		if( v & 0x80 )
		{	/* dump */
			if( v & 0x20 ) RhythmStop(n,RY_RIM);
			if( v & 0x10 ) RhythmStop(n,RY_TOM);
			if( v & 0x08 ) RhythmStop(n,RY_HH);
			if( v & 0x04 ) RhythmStop(n,RY_TOP);
			if( v & 0x02 ) RhythmStop(n,RY_SD);
			if( v & 0x01 ) RhythmStop(n,RY_BD);
		}
		else
		{	/* key on */
			if( v & 0x20 ) RhythmStart(n,RY_RIM);
			if( v & 0x10 ) RhythmStart(n,RY_TOM);
			if( v & 0x08 ) RhythmStart(n,RY_HH);
			if( v & 0x04 ) RhythmStart(n,RY_TOP);
			if( v & 0x02 ) RhythmStart(n,RY_SD);
			if( v & 0x01 ) RhythmStart(n,RY_BD);
		}
		break;
	case 0x11:	/* B0-5 = RTL */
		F2608->RTL = (v & 0x3f);
		break;
	case 0x18:	/* BD  : B7=L,B6=R,B4-0=IL */
	case 0x19:	/* SD  : B7=L,B6=R,B4-0=IL */
	case 0x1A:	/* TOP : B7=L,B6=R,B4-0=IL */
	case 0x1B:	/* HH  : B7=L,B6=R,B4-0=IL */
	case 0x1C:	/* TOM : B7=L,B6=R,B4-0=IL */
	case 0x1D:	/* RIM : B7=L,B6=R,B4-0=IL */
		c = r & 0x18;
		/* B7=L,B6=R,B4-0=BD IL */
		F2608->RPAN[c] = v>>6;
		F2608->RIL[c] = v&0x1f;
		break;
	}
}

/* ---------- IRQ flag Controll Write 0x110 ---------- */
INLINE void YM2608IRQFlagWrite(FM_ST *ST,int n,int v)
{
	if( v & 0x80 )
	{	/* Reset IRQ flag */
		ST->status = 0x00;
	}
	else
	{	/* Set IRQ mask */
		ST->irqmask = v & 0x1f;
	}
	/* IRQ handling */
	if( ST->status & ST->irqmask )
	{
		if( !(ST->irq) )
		{
			ST->irq = 1;
			/* callback user interrupt handler */
			if(EXIRQHandler) EXIRQHandler(n,1);
		}
	}
	else
	{
		if( ST->irq )
		{
			ST->irq = 0;
			/* callback user interrupt handler */
			if(EXIRQHandler) EXIRQHandler(n,0);
		}
	}
}

/* ---------- update one of chip ----------- */
void YM2608UpdateOne(int num, FMSAMPLE **buffer, int length)
{
	YM2608 *F2608 = &(FM2608[num]);
	FM_OPN *OPN   = &(FM2608[num].OPN);
	int dataR,dataL;
	int i,ch;

	/* set bufer */
	bufL = buffer[0];
	bufR = buffer[1];

	if( (void *)F2608 != cur_chip ){
		cur_chip = (void *)F2608;

		State = &OPN->ST;
		cch[0]   = &F2608->CH[0];
		cch[1]   = &F2608->CH[1];
		cch[2]   = &F2608->CH[2];
		cch[3]   = &F2608->CH[3];
		cch[4]   = &F2608->CH[4];
		cch[5]   = &F2608->CH[5];
	}
	/* update frequency counter */
	CALC_FCOUNT( cch[0] );
	CALC_FCOUNT( cch[1] );
	if( (State->mode & 0xc0) ){
		/* 3SLOT MODE */
		if( cch[2]->SLOT[SLOT1].Incr==-1){
			/* 3 slot mode */
			CALC_FCSLOT(&cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] );
			CALC_FCSLOT(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] );
			CALC_FCSLOT(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] );
			CALC_FCSLOT(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode );
		}
	}else CALC_FCOUNT( cch[2] );
	CALC_FCOUNT( cch[3] );
	CALC_FCOUNT( cch[4] );
	CALC_FCOUNT( cch[5] );
	/* buffering */
    for( i=0; i < length ; i++ )
	{
		/* clear output acc. */
		outd[OPN_LEFT] = outd[OPN_RIGHT]= outd[OPN_CENTER] = 0;
		/* calcrate FM */

⌨️ 快捷键说明

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