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

📄 fm.c

📁 这个是延伸mame的在wince平台下的游戏模拟器的代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		for( ch=0;ch<6;ch++) FM_CALC_CH( cch[ch] );
		/* get left & right output */
		dataL = Limit( outd[OPN_CENTER] + outd[OPN_LEFT], OPN_MAXOUT, OPN_MINOUT );
		dataR = Limit( outd[OPN_CENTER] + outd[OPN_RIGHT], OPN_MAXOUT, OPN_MINOUT );
		/* buffering */
		if( sample_16bit )
		{
#ifdef FM_STEREO_MIX		/* stereo mixing */
			/* stereo mix */
			((unsigned long *)bufL)[i] = ((dataL>>OPN_OUTSB)<<16)|(dataR>>OPN_OUTSB);
#else
			/* stereo separate */
			((unsigned short *)bufL)[i] = dataL>>OPN_OUTSB;
			((unsigned short *)bufR)[i] = dataR>>OPN_OUTSB;
#endif
		}
		else
		{
#ifdef FM_STEREO_MIX		/* stereo mixing */
			/* stereo mix */
			((unsigned shart *)bufL)[i] = ((dataL>>OPN_OUTSB_8)<<8)|(dataR>>OPN_OUTSB_8);
#else
			/* stereo separate */
			((unsigned char *)bufL)[i] = dataL>>OPN_OUTSB_8;
			((unsigned char *)bufR)[i] = dataR>>OPN_OUTSB_8;
#endif
		}

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

/* -------------------------- YM2608(OPNA) ---------------------------------- */
int YM2608Init(int num, int clock, int rate,  int bitsize,
               FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler)

{
	int i,j;

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

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

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

	for ( i = 0 ; i < FMNumChips; i++ ) {
		FM2608[i].OPN.index = i;
		FM2608[i].OPN.type = TYPE_YM2608;
		FM2608[i].OPN.P_CH = FM2608[i].CH;
		FM2608[i].OPN.ST.clock = clock;
		FM2608[i].OPN.ST.rate = rate;
		/* Extend handler */
		FM2608[i].OPN.ST.Timer_Handler = TimerHandler;
		FM2608[i].OPN.ST.IRQ_Handler   = IRQHandler;
		YM2608ResetChip(i);
	}
	return 0;
}

/* ---------- shut down emurator ----------- */
void YM2608Shutdown()
{
    if (!FM2608) return;

	FMCloseTable();
	free(FM2608);
	FM2608 = NULL;
}

/* ---------- reset one of chip ---------- */
void YM2608ResetChip(int num)
{
	int i;
	YM2608 *F2608 = &(FM2608[num]);
	FM_OPN *OPN   = &(FM2608[num].OPN);

	/* Reset Priscaler */
	OPNSetPris( OPN, 6*24, 6*24,4*2); /* OPN 1/6 , SSG 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 , F2608->CH , 6 );
	/* reset OPerator paramater */
	for(i = 0xb6 ; i >= 0xb4 ; i-- )
	{
		OPNWriteReg(OPN,i      ,0xc0);
		OPNWriteReg(OPN,i|0x100,0xc0);
	}
	for(i = 0xb2 ; i >= 0x30 ; i-- )
	{
		OPNWriteReg(OPN,i      ,0);
		OPNWriteReg(OPN,i|0x100,0);
	}
	for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0);
	/* reset ADPCM unit */
	/* reset RITHM unit */
}

/* YM2608 write */
/* n = number  */
/* a = address */
/* v = value   */
int YM2608Write(int n, int a,int v)
{
	YM2608 *F2608 = &(FM2608[n]);
	FM_OPN *OPN   = &(FM2608[n].OPN);
	int addr;

	switch( a&3){
	case 0:	/* address port 0 */
		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*24, 6*24, 4*2); /* OPN 1/6 , SSG 1/4 */
			break;
		case 0x2e:	/* divider sel */
			OPNSetPris( OPN, 3*24, 3*24,2*2); /* OPN 1/3 , SSG 1/2 */
			break;
		case 0x2f:	/* divider sel */
			OPNSetPris( OPN, 2*24, 2*24,1*2); /* OPN 1/2 , SSG 1/1 */
			break;
		}
		break;
	case 1:	/* data port 0    */
		addr = OPN->ST.address;
		switch(addr & 0xf0)
		{
		case 0x00:	/* SSG section */
			/* Write data to SSG emurator */
			SSGWrite(n,a,v);
			break;
		case 0x10:	/* Rhythm section */
			YM2608UpdateReq(n);
			YM2608RhythmWrite(n,F2608->address1,v);
			break;
		case 0x20:	/* Mode Register */
			YM2608UpdateReq(n);
			 OPNWriteMode(OPN,addr,v);
		default:	/* OPN section */
			YM2608UpdateReq(n);
			/* write register */
			 OPNWriteReg(OPN,addr,v);
		}
		break;
	case 2:	/* address port 1 */
		F2608->address1 = v & 0xff;
		break;
	case 3:	/* data port 1    */
		addr = F2608->address1;
		YM2608UpdateReq(n);
		switch( addr & 0xf0 )
		{
		case 0x00:	/* ADPCM PORT */
			YM2608ADPCMWrite(n,addr,v);
			break;
		case 0x10:	/* IRQ Flag controll */
			if( addr == 0x10 )
				YM2608IRQFlagWrite(&(OPN->ST),n,v);
			break;
		default:
			OPNWriteReg(OPN,addr|0x100,v);
		}
	}
	return OPN->ST.irq;
}
unsigned char YM2608Read(int n,int a)
{
	YM2608 *F2608 = &(FM2608[n]);
	int addr = F2608->OPN.ST.address;
	int ret = 0;

	switch( a&3 ){
	case 0:	/* status 0 : YM2203 compatible */
		ret = F2608->OPN.ST.status & 0x83;
		break;
	case 1:	/* status 0 */
		if( addr < 16 ) ret = SSGRead(n);
		break;
	case 2:	/* status 1 : + ADPCM status */
		ret = F2608->OPN.ST.status;
		break;
	case 3:
		ret = 0;
		break;
	}
	return ret;
}

int YM2608TimerOver(int n,int c)
{
	YM2608 *F2608 = &(FM2608[n]);

	if( c )
	{	/* Timer B */
		TimerBOver( n,&(F2608->OPN.ST) );
	}
	else
	{	/* Timer A */
		YM2608UpdateReq(n);
		/* timer update */
		TimerAOver( n,&(F2608->OPN.ST) );
		/* CSM mode key,TL controll */
		if( F2608->OPN.ST.mode & 0x80 )
		{	/* CSM mode total level latch and auto key on */
			CSMKeyControll( &(F2608->CH[2]) );
		}
	}
	return FM2608->OPN.ST.irq;
}

#if 0
/* ---------- return the buffer ---------- */
FMSAMPLE **YM2608Buffer(int n)
{
    return &(FM2608[n].Buf);
}
#endif

#if 0
/* ---------- set buffer ---------- */
int YM2608SetBuffer(int n, FMSAMPLE **buf )
{
	int i;
	for( i = 0 ; i < YM2608_NUMBUF ; i++){
		FM2608[n].Buf[i] = buf[i];
		if( cur_chip == &FM2608[n] ) cur_chip = NULL;
	}
	return 0;
}
#endif

#endif /* BUILD_YM2608 */

#ifdef BUILD_YM2610

#define ADPCM_DECODE_RANGE 32768
#define ADPCM_DECODE_MIN (-ADPCM_DECODE_RANGE+1)
#define ADPCM_DECODE_MAX (ADPCM_DECODE_RANGE-1)

/* -------------------------- YM2610(OPNB) ---------------------------------- */
/***************************************************************/
/*    ADPCM units are made by Hiromitsu Shioya (MMSND)         */
/***************************************************************/

static YM2610 *FM2610=NULL;	/* array of YM2610's */

static char         *pcmbufA, *pcmbufB;
static unsigned int pcmsizeA, pcmsizeB;

/************************************************************/
/************************************************************/
/* --------------------- subroutines  --------------------- */
/************************************************************/
/************************************************************/
static int decode_table1[16] = {
  1,   3,   5,   7,   9,  11,  13,  15,
  -1,  -3,  -5,  -7,  -9, -11, -13, -15,
};
static int decode_table2[16] = {
  57,  57,  57,  57,  77, 102, 128, 153,
  57,  57,  57,  57,  77, 102, 128, 153,
};

/**** ADPCM A(YAMAHA type) *****/
INLINE void OPNB_ADPCM_CALC_CHA( ADPCM_CH *ch )
{
	unsigned int bit, addr, mask, stepaddr, endaddr;
	int data;

	addr = ch->now_addr;
	ch->now_addr += ch->step;
	mask = ~( ( 1 << ADPCM_SHIFT ) -1 );
	if ( ( addr & mask ) < ( ch->now_addr & mask ) ) {
		endaddr = ch->now_addr & mask;
		bit = (((addr & mask)>>(ADPCM_SHIFT-2))&4)^4;
		for ( stepaddr = addr & mask; stepaddr < endaddr; stepaddr += ( 1 << ADPCM_SHIFT ) ) {
			addr = ( ( stepaddr >> ( ADPCM_SHIFT + 1 ) ) & 0x003fffff ) + ch->start;
			if ( addr > ch->end ) {
				ch->flag = 0;
				return;
			}
			if ( addr > pcmsizeA ) {
				return;
			}
			data = ( *( pcmbufA + addr ) >> bit ) & 0x0f;
			bit ^= 4;
			ch->adpcmx = Limit( ch->adpcmx + ( ( decode_table1[data] * ch->adpcmd ) / ADPCMA_CURVE_DIVIDE ), ADPCM_DECODE_MAX, ADPCM_DECODE_MIN );
			ch->adpcmd = Limit( ( ch->adpcmd * decode_table2[data] ) / 64, 24576, 127 );
		}
	}
	/* output for work of output channels (outd[OPNxxxx])*/
	*(ch->pan) += ch->adpcmx * ch->volume;
}

/****************************************************************/
/****************************************************************/
static int jedi_table[16][49];
static int decodeb_table1[16] = {
  -1, -1, -1, -1, 2, 5, 7, 9,
  -1, -1, -1, -1, 2, 5, 7, 9
};

static int decodeb_table2[49] = {
  0x0010, 0x0011, 0x0013, 0x0015, 0x0017, 0x0019, 0x001c, 0x001f,
  0x0022, 0x0025, 0x0029, 0x002d, 0x0032, 0x0037, 0x003c, 0x0042,
  0x0049, 0x0050, 0x0058, 0x0061, 0x006b, 0x0076, 0x0082, 0x008f,
  0x009d, 0x00ad, 0x00be, 0x00d1, 0x00e6, 0x00fd, 0x0117, 0x0133,
  0x0151, 0x0173, 0x0198, 0x01c1, 0x01ee, 0x0220, 0x0256, 0x0292,
  0x02d4, 0x031c, 0x036c, 0x03c3, 0x0424, 0x048e, 0x0502, 0x0583,
  0x0610
};
static void InitOPNB_ADPCMBTable(void){
   int ta,tb,tc;
   for(ta=0;ta<49;ta++){
     for(tb=0;tb<16;tb++){
       tc=0;
       if(tb&0x04){tc+=(decodeb_table2[ta]);}
       if(tb&0x02){tc+=(decodeb_table2[ta]>>1);}
       if(tb&0x01){tc+=(decodeb_table2[ta]>>2);}
       tc+=(decodeb_table2[ta]>>3);
       if(tb&0x08){tc=(0-tc);}
       jedi_table[tb][ta]=tc;
     }
   }
}

/**** ADPCM B(OKI? type)*****/
INLINE void OPNB_ADPCM_CALC_CHB( ADPCM_CH *ch )
{
	unsigned int bit, addr, mask, stepaddr, endaddr;
	int data;

	addr = ch->now_addr;
	ch->now_addr += ch->step;
	mask = ~( ( 1 << ADPCM_SHIFT ) -1 );

	if ( ( addr & mask ) < ( ch->now_addr & mask ) ) {
		endaddr = ch->now_addr & mask;
		bit = (((addr & mask)>>(ADPCM_SHIFT-2))&4)^4;
		for( stepaddr = addr & mask; stepaddr < endaddr; stepaddr += ( 1 << ADPCM_SHIFT ) ) {
			addr = ( ( stepaddr >> ( ADPCM_SHIFT + 1 ) ) & 0x003fffff ) + ch->start;
			if ( addr > ch->end ) {
				ch->flag = 0;
				return;
			}
			if ( addr > pcmsizeB ) {
				return;
			}
			data = ( *( pcmbufB + addr ) >> bit ) & 0x0f;
			bit ^= 4;

			ch->adpcmx = Limit( ch->adpcmx + (jedi_table[data][ch->adpcmd] / ADPCMB_CURVE_DIVIDE), (ADPCM_DECODE_MAX>>0), (ADPCM_DECODE_MIN>>0) );
			ch->adpcmd = Limit( ch->adpcmd + decodeb_table1[data], 48, 0 );
		}
	}
	/* output for work of output channels (outd[OPNxxxx])*/
	*(ch->pan) += ch->adpcmx * ch->volume;
}

/* ---------- update one of chip ----------- */
void YM2610UpdateOne(int num, FMSAMPLE **buffer, int length)
{
	YM2610 *F2610 = &(FM2610[num]);
	FM_OPN *OPN   = &(FM2610[num].OPN);
#ifndef FM_OUTPUT_PROC
	static FMSAMPLE  *buf[YM2610_NUMBUF];
#else
	static unsigned char  *buf[YM2610_NUMBUF];
#endif
	int dataR,dataL;
	int i,j;

	/* buffer setup */
#ifndef FM_OUTPUT_PROC
	for( i = 0; i < YM2610_NUMBUF; i++ )  buf[i] = buffer[i];
#else
	for( i = 0; i < YM2610_NUMBUF; i++ )  buf[i] = (unsigned char *)buffer[i];
#endif

	if( (void *)F2610 != cur_chip ){
		cur_chip = (void *)F2610;
		State = &OPN->ST;
		cch[0] = &F2610->CH[0];
		cch[1] = &F2610->CH[1];
		cch[2] = &F2610->CH[2];
		cch[3] = &F2610->CH[3];
		cch[4] = &F2610->CH[4];
		cch[5] = &F2610->CH[5];
		/* setup adpcm rom address */
		pcmbufA  = F2610->pcmbuf[0];
		pcmsizeA = F2610->pcm_size[0];
		pcmbufB  = F2610->pcmbuf[1];
		pcmsizeB = F2610->pcm_size[1];
	}

	/* 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;
		/**** deltaT ADPCM ****/
		if( F2610->adpcm[6].flag )
		{
			OPNB_ADPCM_CALC_CHA( &F2610->adpcm[6]);
			if( F2610->adpcm[6].flag == 0)
					F2610->adpcm_justfinished |= F2610->adpcm[6].flagMask & F2610->adpcm_statusmask;
		}
		/* FM */
		FM_CALC_CH( cch[1] );
		FM_CALC_CH( cch[2] );
		FM_CALC_CH( cch[4] );
		FM_CALC_CH( cch[5] );
		for( j = 0; j < 6; j++ )
		{
			/**** ADPCM ****/

⌨️ 快捷键说明

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