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

📄 fmopl.c.bak

📁 DC的SEGA_GG模拟器源代码
💻 BAK
📖 第 1 页 / 共 3 页
字号:
					}
					else
					{
						OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1]);
						OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2]);
					}
				}
				/* SD key on/off */
				if(rkey&0x08)
				{
					if(v&0x08) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT2]);
					else       OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2]);
				}/* TAM key on/off */
				if(rkey&0x04)
				{
					if(v&0x04) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT1]);
					else       OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1]);
				}
				/* TOP-CY key on/off */
				if(rkey&0x02)
				{
					if(v&0x02) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT2]);
					else       OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2]);
				}
				/* HH key on/off */
				if(rkey&0x01)
				{
					if(v&0x01) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT1]);
					else       OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1]);
				}
			}
			}
			return;
		}
		/* keyon,block,fnum */
		if( (r&0x0f) > 8) return;
		CH = &OPL->P_CH[r&0x0f];
		if(!(r&0x10))
		{	/* a0-a8 */
			block_fnum  = (CH->block_fnum&0x1f00) | v;
		}
		else
		{	/* b0-b8 */
			int keyon = (v>>5)&1;
			block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff);
			if(CH->keyon != keyon)
			{
				if( (CH->keyon=keyon) )
				{
					CH->op1_out[0] = CH->op1_out[1] = 0;
					OPL_KEYON(&CH->SLOT[SLOT1]);
					OPL_KEYON(&CH->SLOT[SLOT2]);
				}
				else
				{
					OPL_KEYOFF(&CH->SLOT[SLOT1]);
					OPL_KEYOFF(&CH->SLOT[SLOT2]);
				}
			}
		}
		/* update */
		if(CH->block_fnum != block_fnum)
		{
			int blockRv = 7-(block_fnum>>10);
			int fnum   = block_fnum&0x3ff;
			CH->block_fnum = block_fnum;

			CH->ksl_base = KSL_TABLE[block_fnum>>6];
			CH->fc = OPL->FN_TABLE[fnum]>>blockRv;
			CH->kcode = CH->block_fnum>>9;
			if( (OPL->mode&0x40) && CH->block_fnum&0x100) CH->kcode |=1;
			CALC_FCSLOT(CH,&CH->SLOT[SLOT1]);
			CALC_FCSLOT(CH,&CH->SLOT[SLOT2]);
		}
		return;
	case 0xc0:
		/* FB,C */
		if( (r&0x0f) > 8) return;
		CH = &OPL->P_CH[r&0x0f];
		{
		int feedback = (v>>1)&7;
		CH->FB   = feedback ? (8+1) - feedback : 0;
		CH->CON = v&1;
		set_algorythm(CH);
		}
		return;
	case 0xe0: /* wave type */
		slot = slot_array[r&0x1f];
		if(slot == -1) return;
		CH = &OPL->P_CH[slot/2];
		if(OPL->wavesel)
		{
			/* Log(LOG_INF,"OPL SLOT %d wave select %d\n",slot,v&3); */
			CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v&0x03)*SIN_ENT];
		}
		return;
	}
}

/* lock/unlock for common table */
static int OPL_LockTable(void)
{
	num_lock++;
	if(num_lock>1) return 0;
	/* first time */
	cur_chip = NULL;
	/* allocate total level table (128kb space) */
	if( !OPLOpenTable() )
	{
		num_lock--;
		return -1;
	}
	return 0;
}

static void OPL_UnLockTable(void)
{
	if(num_lock) num_lock--;
	if(num_lock) return;
	/* last time */
	cur_chip = NULL;
	OPLCloseTable();
}

#if (BUILD_YM3812 || BUILD_YM3526)
/*******************************************************************************/
/*		YM3812 local section                                                   */
/*******************************************************************************/

/* ---------- update one of chip ----------- */
void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
{
    int i;
	int data;
	FMSAMPLE *buf = buffer;
	UINT32 amsCnt  = OPL->amsCnt;
	UINT32 vibCnt  = OPL->vibCnt;
	UINT8 rythm = OPL->rythm&0x20;
	OPL_CH *CH,*R_CH;

	if( (void *)OPL != cur_chip ){
		cur_chip = (void *)OPL;
		/* channel pointers */
		S_CH = OPL->P_CH;
		E_CH = &S_CH[9];
		/* rythm slot */
		SLOT7_1 = &S_CH[7].SLOT[SLOT1];
		SLOT7_2 = &S_CH[7].SLOT[SLOT2];
		SLOT8_1 = &S_CH[8].SLOT[SLOT1];
		SLOT8_2 = &S_CH[8].SLOT[SLOT2];
		/* LFO state */
		amsIncr = OPL->amsIncr;
		vibIncr = OPL->vibIncr;
		ams_table = OPL->ams_table;
		vib_table = OPL->vib_table;
	}
	R_CH = rythm ? &S_CH[6] : E_CH;
    for( i=0; i < length ; i++ )
	{
		/*            channel A         channel B         channel C      */
		/* LFO */
		ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];
		vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];
		outd[0] = 0;
		/* FM part */
		for(CH=S_CH ; CH < R_CH ; CH++)
			OPL_CALC_CH(CH);
		/* Rythn part */
		if(rythm)
			OPL_CALC_RH(S_CH);
		/* limit check */
		data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
		/* store to sound buffer */
		buf[i] = data >> OPL_OUTSB;
	}

	OPL->amsCnt = amsCnt;
	OPL->vibCnt = vibCnt;
}
#endif /* (BUILD_YM3812 || BUILD_YM3526) */

#if BUILD_Y8950

void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
{
    int i;
	int data;
	FMSAMPLE *buf = buffer;
	UINT32 amsCnt  = OPL->amsCnt;
	UINT32 vibCnt  = OPL->vibCnt;
	UINT8 rythm = OPL->rythm&0x20;
	OPL_CH *CH,*R_CH;
	YM_DELTAT *DELTAT = OPL->deltat;

	/* setup DELTA-T unit */
	YM_DELTAT_DECODE_PRESET(DELTAT);

	if( (void *)OPL != cur_chip ){
		cur_chip = (void *)OPL;
		/* channel pointers */
		S_CH = OPL->P_CH;
		E_CH = &S_CH[9];
		/* rythm slot */
		SLOT7_1 = &S_CH[7].SLOT[SLOT1];
		SLOT7_2 = &S_CH[7].SLOT[SLOT2];
		SLOT8_1 = &S_CH[8].SLOT[SLOT1];
		SLOT8_2 = &S_CH[8].SLOT[SLOT2];
		/* LFO state */
		amsIncr = OPL->amsIncr;
		vibIncr = OPL->vibIncr;
		ams_table = OPL->ams_table;
		vib_table = OPL->vib_table;
	}
	R_CH = rythm ? &S_CH[6] : E_CH;
    for( i=0; i < length ; i++ )
	{
		/*            channel A         channel B         channel C      */
		/* LFO */
		ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];
		vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];
		outd[0] = 0;
		/* deltaT ADPCM */
		if( DELTAT->flag )
			YM_DELTAT_ADPCM_CALC(DELTAT);
		/* FM part */
		for(CH=S_CH ; CH < R_CH ; CH++)
			OPL_CALC_CH(CH);
		/* Rythn part */
		if(rythm)
			OPL_CALC_RH(S_CH);
		/* limit check */
		data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
		/* store to sound buffer */
		buf[i] = data >> OPL_OUTSB;
	}
	OPL->amsCnt = amsCnt;
	OPL->vibCnt = vibCnt;
	/* deltaT START flag */
	if( !DELTAT->flag )
		OPL->status &= 0xfe;
}
#endif

/* ---------- reset one of chip ---------- */
void OPLResetChip(FM_OPL *OPL)
{
	int c,s;
	int i;

	/* reset chip */
	OPL->mode   = 0;	/* normal mode */
	OPL_STATUS_RESET(OPL,0x7f);
	/* reset with register write */
	OPLWriteReg(OPL,0x01,0); /* wabesel disable */
	OPLWriteReg(OPL,0x02,0); /* Timer1 */
	OPLWriteReg(OPL,0x03,0); /* Timer2 */
	OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */
	for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0);
	/* reset OPerator paramater */
	for( c = 0 ; c < OPL->max_ch ; c++ )
	{
		OPL_CH *CH = &OPL->P_CH[c];
		/* OPL->P_CH[c].PAN = OPN_CENTER; */
		for(s = 0 ; s < 2 ; s++ )
		{
			/* wave table */
			CH->SLOT[s].wavetable = &SIN_TABLE[0];
			/* CH->SLOT[s].evm = ENV_MOD_RR; */
			CH->SLOT[s].evc = EG_OFF;
			CH->SLOT[s].eve = EG_OFF+1;
			CH->SLOT[s].evs = 0;
		}
	}
#if BUILD_Y8950
	if(OPL->type&OPL_TYPE_ADPCM)
	{
		YM_DELTAT *DELTAT = OPL->deltat;

		DELTAT->freqbase = OPL->freqbase;
		DELTAT->output_pointer = outd;
		DELTAT->portshift = 5;
		DELTAT->output_range = DELTAT_MIXING_LEVEL<<TL_BITS;
		YM_DELTAT_ADPCM_Reset(DELTAT,0);
	}
#endif
}

/* ----------  Create one of vietual YM3812 ----------       */
/* 'rate'  is sampling rate and 'bufsiz' is the size of the  */
FM_OPL *OPLCreate(int type, int clock, int rate)
{
	char *ptr;
	FM_OPL *OPL;
	int state_size;
	int max_ch = 9; /* normaly 9 channels */

	if( OPL_LockTable() ==-1) return NULL;
	/* allocate OPL state space */
	state_size  = sizeof(FM_OPL);
	state_size += sizeof(OPL_CH)*max_ch;
#if BUILD_Y8950
	if(type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT);
#endif
	/* allocate memory block */
	ptr = malloc(state_size);
	if(ptr==NULL) return NULL;
	/* clear */
	memset(ptr,0,state_size);
	OPL        = (FM_OPL *)ptr; ptr+=sizeof(FM_OPL);
	OPL->P_CH  = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch;
#if BUILD_Y8950
	if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT);
#endif
	/* set channel state pointer */
	OPL->type  = type;
	OPL->clock = clock;
	OPL->rate  = rate;
	OPL->max_ch = max_ch;
	/* init grobal tables */
	OPL_initalize(OPL);
	/* reset chip */
	OPLResetChip(OPL);
	return OPL;
}

/* ----------  Destroy one of vietual YM3812 ----------       */
void OPLDestroy(FM_OPL *OPL)
{
	OPL_UnLockTable();
	free(OPL);
}

/* ----------  Option handlers ----------       */

void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset)
{
	OPL->TimerHandler   = TimerHandler;
	OPL->TimerParam = channelOffset;
}
void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param)
{
	OPL->IRQHandler     = IRQHandler;
	OPL->IRQParam = param;
}
void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param)
{
	OPL->UpdateHandler = UpdateHandler;
	OPL->UpdateParam = param;
}
#if BUILD_Y8950
void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param)
{
	OPL->porthandler_w = PortHandler_w;
	OPL->porthandler_r = PortHandler_r;
	OPL->port_param = param;
}

void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param)
{
	OPL->keyboardhandler_w = KeyboardHandler_w;
	OPL->keyboardhandler_r = KeyboardHandler_r;
	OPL->keyboard_param = param;
}
#endif
/* ---------- YM3812 I/O interface ---------- */
int OPLWrite(FM_OPL *OPL,int a,int v)
{
	if( !(a&1) )
	{	/* address port */
		OPL->address = v & 0xff;
	}
	else
	{	/* data port */
		if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
		OPLWriteReg(OPL,OPL->address,v);
	}
	return OPL->status>>7;
}

unsigned char OPLRead(FM_OPL *OPL,int a)
{
	if( !(a&1) )
	{	/* status port */
		return OPL->status & (OPL->statusmask|0x80);
	}
	/* data port */
	switch(OPL->address)
	{
	case 0x05: /* KeyBoard IN */
		if(OPL->type&OPL_TYPE_KEYBOARD)
		{
			if(OPL->keyboardhandler_r)
				return OPL->keyboardhandler_r(OPL->keyboard_param);
			else
				Log(LOG_WAR,"OPL:read unmapped KEYBOARD port\n");
		}
		return 0;
#if 0
	case 0x0f: /* ADPCM-DATA  */
		return 0;
#endif
	case 0x19: /* I/O DATA    */
		if(OPL->type&OPL_TYPE_IO)
		{
			if(OPL->porthandler_r)
				return OPL->porthandler_r(OPL->port_param);
			else
				Log(LOG_WAR,"OPL:read unmapped I/O port\n");
		}
		return 0;
	case 0x1a: /* PCM-DATA    */
		return 0;
	}
	return 0;
}

int OPLTimerOver(FM_OPL *OPL,int c)
{
	if( c )
	{	/* Timer B */
		OPL_STATUS_SET(OPL,0x20);
	}
	else
	{	/* Timer A */
		OPL_STATUS_SET(OPL,0x40);
		/* CSM mode key,TL controll */
		if( OPL->mode & 0x80 )
		{	/* CSM mode total level latch and auto key on */
			int ch;
			if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
			for(ch=0;ch<9;ch++)
				CSMKeyControll( &OPL->P_CH[ch] );
		}
	}
	/* reload timer */
	if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase);
	return OPL->status>>7;
}

⌨️ 快捷键说明

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