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

📄 fm.c

📁 十七种模拟器源代码 非常有用的作课程设计不可缺少的
💻 C
📖 第 1 页 / 共 5 页
字号:
		FM_STATUS_RESET(ST,0xff);	}	else	{	/* Set IRQ mask */		/* !!!!!!!!!! pending !!!!!!!!!! */	}}#ifdef YM2608_RHYTHM_PCM/**** RYTHM (PCM) ****/INLINE void YM2608_RYTHM( YM2608 *F2608, ADPCM_CH *ch ){	UINT32 step;	ch->now_step += ch->step;	if ( ch->now_step >= (1<<ADPCM_SHIFT) )	{		step = ch->now_step >> ADPCM_SHIFT;		ch->now_step &= (1<<ADPCM_SHIFT)-1;		/* end check */		if ( (ch->now_addr+step) > (ch->end<<1) ) {			ch->flag = 0;			F2608->adpcm_arrivedEndAddress |= ch->flagMask;			return;		}		do{			/* get a next pcm data */			ch->adpcmx = ((short *)pcmbufA)[ch->now_addr];			ch->now_addr++;			/**** calc pcm * volume data ****/			ch->adpcml = ch->adpcmx * ch->volume;		}while(--step);	}	/* output for work of output channels (out_ch[OPNxxxx])*/	*(ch->pan) += ch->adpcml;}#endif /* YM2608_RHYTHM_PCM *//* ---------- update one of chip ----------- */void YM2608UpdateOne(int num, INT16 **buffer, int length){	YM2608 *F2608 = &(FM2608[num]);	FM_OPN *OPN   = &(FM2608[num].OPN);	YM_DELTAT *DELTAT = &(F2608[num].deltaT);	int i,j;	FM_CH *ch;	FMSAMPLE  *bufL,*bufR;	/* setup DELTA-T unit */	YM_DELTAT_DECODE_PRESET(DELTAT);	DELTAT->arrivedFlag = 0;	/* ASG */	DELTAT->flagMask = 1;	/* ASG */	/* 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];		/* setup adpcm rom address */		pcmbufA  = F2608->pcmbuf;		pcmsizeA = F2608->pcm_size;#if FM_LFO_SUPPORT		LFOCnt  = OPN->LFOCnt;		LFOIncr = OPN->LFOIncr;		if( !LFOIncr ) lfo_amd = lfo_pmd = 0;#endif	}	/* update frequency counter */	OPN_CALC_FCOUNT( cch[0] );	OPN_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 OPN_CALC_FCOUNT( cch[2] );	OPN_CALC_FCOUNT( cch[3] );	OPN_CALC_FCOUNT( cch[4] );	OPN_CALC_FCOUNT( cch[5] );	/* buffering */    for( i=0; i < length ; i++ )	{#if FM_LFO_SUPPORT		/* LFO */		if( LFOIncr )		{			lfo_amd = OPN_LFO_wave[(LFOCnt+=LFOIncr)>>LFO_SHIFT];			lfo_pmd = lfo_amd-(LFO_RATE/2);		}#endif		/* clear output acc. */		out_ch[OUTD_LEFT] = out_ch[OUTD_RIGHT]= out_ch[OUTD_CENTER] = 0;		/**** deltaT ADPCM ****/		if( DELTAT->flag )			YM_DELTAT_ADPCM_CALC(DELTAT);		/* FM */		for(ch = cch[0] ; ch <= cch[5] ; ch++)			FM_CALC_CH( ch );		for( j = 0; j < 6; j++ )		{			/**** ADPCM ****/			if( F2608->adpcm[j].flag )#ifdef YM2608_RHYTHM_PCM				YM2608_RYTHM(F2608, &F2608->adpcm[j]);#else				OPNB_ADPCM_CALC_CHA( F2608, &F2608->adpcm[j]);#endif		}		/* buffering */		FM_BUFFERING_STEREO;		/* timer A controll */		INTERNAL_TIMER_A( State , cch[2] )	}	INTERNAL_TIMER_B(State,length)	if (DELTAT->arrivedFlag) FM_STATUS_SET(State, 0x04);	/* ASG */#if FM_LFO_SUPPORT	OPN->LFOCnt = LFOCnt;#endif}/* -------------------------- YM2608(OPNA) ---------------------------------- */int YM2608Init(int num, int clock, int rate,               void **pcmrom,int *pcmsize,short *rhythmrom,int *rhythmpos,               FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler){	int i,j;    if (FM2608) return (-1);	/* duplicate init. */    cur_chip = NULL;	/* hiro-shi!! */	YM2608NumChips = num;	/* allocate extend state space */	if( (FM2608 = (YM2608 *)malloc(sizeof(YM2608) * YM2608NumChips))==NULL)		return (-1);	/* clear */	memset(FM2608,0,sizeof(YM2608) * YM2608NumChips);	/* allocate total level table (128kb space) */	if( !OPNInitTable() )	{		free( FM2608 );		return (-1);	}	for ( i = 0 ; i < YM2608NumChips; i++ ) {		FM2608[i].OPN.ST.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;		/* FM2608[i].OPN.ST.irq = 0; */		/* FM2608[i].OPN.ST.status = 0; */		FM2608[i].OPN.ST.timermodel = FM_TIMER_INTERVAL;		/* Extend handler */		FM2608[i].OPN.ST.Timer_Handler = TimerHandler;		FM2608[i].OPN.ST.IRQ_Handler   = IRQHandler;		/* DELTA-T */		FM2608[i].deltaT.memory = (UINT8 *)(pcmrom[i]);		FM2608[i].deltaT.memory_size = pcmsize[i];		/* ADPCM(Rythm) */		FM2608[i].pcmbuf   = (UINT8 *)rhythmrom;#ifdef YM2608_RHYTHM_PCM		/* rhythm sound setup (PCM) */		for(j=0;j<6;j++)		{			/* rhythm sound */			FM2608[i].adpcm[j].start = rhythmpos[j];			FM2608[i].adpcm[j].end   = rhythmpos[j+1]-1;		}		FM2608[i].pcm_size = rhythmpos[6];#else		/* rhythm sound setup (ADPCM) */		FM2608[i].pcm_size = rhythmsize;#endif		YM2608ResetChip(i);	}	InitOPNB_ADPCMATable();	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);	YM_DELTAT *DELTAT = &(F2608[num].deltaT);	/* Reset Priscaler */	OPNSetPris( OPN, 6*24, 6*24,4*2); /* OPN 1/6 , SSG 1/4 */	/* reset SSG section */	SSGReset(OPN->ST.index);	/* status clear */	FM_IRQMASK_SET(&OPN->ST,0x1f);	OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */	/* extend 3ch. disable */	/*OPN->type &= (~TYPE_6CH); */	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 */	/**** ADPCM work initial ****/	for( i = 0; i < 6+1; i++ ){		F2608->adpcm[i].now_addr  = 0;		F2608->adpcm[i].now_step  = 0;		F2608->adpcm[i].step      = 0;		F2608->adpcm[i].start     = 0;		F2608->adpcm[i].end       = 0;		/* F2608->adpcm[i].delta     = 21866; */		F2608->adpcm[i].volume    = 0;		F2608->adpcm[i].pan       = &out_ch[OUTD_CENTER]; /* default center */		F2608->adpcm[i].flagMask  = (i == 6) ? 0x20 : 0;		F2608->adpcm[i].flag      = 0;		F2608->adpcm[i].adpcmx    = 0;		F2608->adpcm[i].adpcmd    = 127;		F2608->adpcm[i].adpcml    = 0;	}	F2608->adpcmTL = &(TL_TABLE[0x3f*(int)(0.75/EG_STEP)]);	/* F2608->port1state = -1; */	F2608->adpcm_arrivedEndAddress = 0; /* don't used */	/* DELTA-T unit */	DELTAT->freqbase = OPN->ST.freqbase;	DELTAT->output_pointer = out_ch;	DELTAT->portshift = 5;		/* allways 5bits shift */ /* ASG */	DELTAT->output_range = DELTAT_MIXING_LEVEL<<TL_BITS;	YM_DELTAT_ADPCM_Reset(DELTAT,OUTD_CENTER);}/* YM2608 write *//* n = number  *//* a = address *//* v = value   */int YM2608Write(int n, int a,UINT8 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 */			F2608->deltaT.freqbase = OPN->ST.freqbase;			break;		case 0x2e:	/* divider sel */			OPNSetPris( OPN, 3*24, 3*24,2*2); /* OPN 1/3 , SSG 1/2 */			F2608->deltaT.freqbase = OPN->ST.freqbase;			break;		case 0x2f:	/* divider sel */			OPNSetPris( OPN, 2*24, 2*24,1*2); /* OPN 1/2 , SSG 1/1 */			F2608->deltaT.freqbase = OPN->ST.freqbase;			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:	/* 0x10-0x1f : Rhythm section */			YM2608UpdateReq(n);			FM_ADPCMAWrite(F2608,addr-0x10,v);			break;		case 0x20:	/* Mode Register */			switch(addr)			{			case 0x29: /* SCH,xirq mask */				/* SCH,xx,xxx,EN_ZERO,EN_BRDY,EN_EOS,EN_TB,EN_TA */				/* extend 3ch. enable/disable */				if(v&0x80) OPN->type |= TYPE_6CH;				else       OPN->type &= ~TYPE_6CH;				/* IRQ MASK */				FM_IRQMASK_SET(&OPN->ST,v&0x1f);				break;			default:				YM2608UpdateReq(n);				OPNWriteMode(OPN,addr,v);			}			break;		default:	/* OPN section */			YM2608UpdateReq(n);			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 */			switch( addr )			{			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; */				/*FM_STATUS_RESET(F2608->OPN.ST,0x08); */				break;			default:				/* 0x00-0x0b */				YM_DELTAT_ADPCM_Write(&F2608->deltaT,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;}UINT8 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 */		/* BUSY:x:x:x:x:x:FLAGB:FLAGA */		if(addr==0xff) ret = 0x00; /* ID code */		else ret = F2608->OPN.ST.status & 0x83;		break;	case 1:	/* status 0 */		if( addr < 16 ) ret = SSGRead(n);		break;	case 2:	/* status 1 : + ADPCM status */		/* BUSY:x:PCMBUSY:ZERO:BRDY:EOS:FLAGB:FLAGA */		if(addr==0xff) ret = 0x00; /* ID code */		else ret = F2608->OPN.ST.status | (F2608->adpcm[6].flag ? 0x20 : 0);		break;	case 3:		ret = 0;		break;	}	return ret;}int YM2608TimerOver(int n,int c){	YM2608 *F2608 = &(FM2608[n]);	if( c )	{	/* Timer B */		TimerBOver( &(F2608->OPN.ST) );	}	else	{	/* Timer A */		YM2608UpdateReq(n);		/* timer update */		TimerAOver( &(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;}#endif /* BUILD_YM2608 */#if BUILD_OPNB/* -------------------------- YM2610(OPNB) ---------------------------------- */static YM2610 *FM2610=NULL;	/* array of YM2610's */static int YM2610NumChips;	/* total chip *//* ---------- update one of chip (YM2610B FM6: ADPCM-A6: ADPCM-B:1) ----------- */void YM2610UpdateOne(int num, INT16 **buffer, int length){	YM2610 *F2610 = &(FM2610[num]);	FM_OPN *OPN   = &(FM2610[num].OPN);	YM_DELTAT *DELTAT = &(F2610[num].deltaT);	int i,j;	int ch;	FMSAMPLE  *bufL,*bufR;	/* setup DELTA-T unit */	YM_DELTAT_DECODE_PRESET(DELTAT);	/* buffer setup */	bufL = buffer[0];	bufR = buffer[1];	if( (void *)F2610 != cur_chip ){		cur_chip = (void *)F2610;		State = &OPN->ST;		cch[0] = &F2610->CH[1];		cch[1] = &F2610->CH[2];		cch[2] = &F2610->CH[4];		cch[3] = &F2610->CH[5];		/* setup adpcm rom address */		pcmbufA  = F2610->pcmbuf;		pcmsizeA = F2610->pcm_size;#if FM_LFO_SUPPORT		LFOCnt  = OPN->LFOCnt;		LFOIncr = OPN->LFOIncr;		if( !LFOIncr ) lfo_amd = lfo_pmd = 0;#endif	}#ifdef YM2610B_WARNING#define FM_MSG_YM2610B "YM2610-%d.CH%d is playing,Check whether the type of the chip is YM2610B\n"	/* Check YM2610B worning message *//* 	if( FM_KEY_IS(&F2610->CH[0].SLOT[3]) ) *//* 		LOG(LOG_WAR,(FM_MSG_YM2610B,num,0)); *//* 	if( FM_KEY_IS(&F2610->CH[3].SLOT[3]) ) *//* 		LOG(LOG_WAR,(FM_MSG_YM2610B,num,3)); */#endi

⌨️ 快捷键说明

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