fm.c
来自「DGen源码最后版本」· C语言 代码 · 共 2,003 行 · 第 1/5 页
C
2,003 行
CH->connect2 = carrier;
CH->connect3 = carrier;
break;
case 6:
/* PG---S1---S2-+ */
/* PG--------S3-+-OUT */
/* PG--------S4-+ */
CH->connect1 = &feedback2;
CH->connect2 = carrier;
CH->connect3 = carrier;
break;
case 7:
/* PG---S1-+ */
/* PG---S2-+-OUT */
/* PG---S3-+ */
/* PG---S4-+ */
CH->connect1 = carrier;
CH->connect2 = carrier;
CH->connect3 = carrier;
}
CH->connect4 = carrier;
}
/* set detune & multiple */
INLINE void set_det_mul(FM_ST *ST,FM_CH *CH,FM_SLOT *SLOT,int v)
{
SLOT->mul = MUL_TABLE[v&0x0f];
SLOT->DT = ST->DT_TABLE[(v>>4)&7];
CH->SLOT[SLOT1].Incr=-1;
}
/* set total level */
INLINE void set_tl(FM_CH *CH,FM_SLOT *SLOT , int v,int csmflag)
{
v &= 0x7f;
v = (v<<7)|v; /* 7bit -> 14bit */
SLOT->TL = (v*EG_ENT)>>14;
if( !csmflag )
{ /* not CSM latch total level */
SLOT->TLL = SLOT->TL + KSL[CH->kcode];
}
}
/* set attack rate & key scale */
INLINE void set_ar_ksr(FM_CH *CH,FM_SLOT *SLOT,int v,signed int *ar_table)
{
SLOT->KSR = 3-(v>>6);
SLOT->AR = (v&=0x1f) ? &ar_table[v<<1] : RATE_0;
SLOT->evsa = SLOT->AR[SLOT->ksr];
if( SLOT->evm == ENV_MOD_AR ) SLOT->evs = SLOT->evsa;
CH->SLOT[SLOT1].Incr=-1;
}
/* set decay rate */
INLINE void set_dr(FM_SLOT *SLOT,int v,signed int *dr_table)
{
SLOT->DR = (v&=0x1f) ? &dr_table[v<<1] : RATE_0;
SLOT->evsd = SLOT->DR[SLOT->ksr];
if( SLOT->evm == ENV_MOD_DR ) SLOT->evs = SLOT->evsd;
}
/* set sustain rate */
INLINE void set_sr(FM_SLOT *SLOT,int v,signed int *dr_table)
{
SLOT->SR = (v&=0x1f) ? &dr_table[v<<1] : RATE_0;
SLOT->evss = SLOT->SR[SLOT->ksr];
if( SLOT->evm == ENV_MOD_SR ) SLOT->evs = SLOT->evss;
}
/* set release rate */
INLINE void set_sl_rr(FM_SLOT *SLOT,int v,signed int *dr_table)
{
SLOT->SL = SL_TABLE[(v>>4)];
SLOT->RR = &dr_table[((v&0x0f)<<2)|2];
SLOT->evsr = SLOT->RR[SLOT->ksr];
if( SLOT->evm == ENV_MOD_RR ) SLOT->evs = SLOT->evsr;
}
//int daves_fb_val=80;
//static int daves_fb[10]={0};
/* operator output calcrator */
#define OP_OUT(slot,env,con) SIN_TABLE[((slot.Cnt+con)/(0x1000000/SIN_ENT))&(SIN_ENT-1)][env]
/* ---------- calcrate one of channel ---------- */
INLINE void FM_CALC_CH( FM_CH *CH )
{
int op_out;
int env_out;
feedback2 = feedback3 = feedback4 = 0;
/*
// dave
if (debug_log)
{
static int count=0;
count++;
if ((count&0xfff)==0)
{
fprintf (debug_log,"count= %10d ",count);
fprintf (debug_log,"CH->FB %d CH->connect1 %p dave_fb %d\n",CH->FB,CH->connect1,daves_fb_val);
}
}
*/
// SLOT 1
env_out=FM_CALC_SLOT(&CH->SLOT[SLOT1]);
if( env_out < EG_ENT-1 )
{
// Original START
if( CH->FB )
{
// with self feed back
op_out = CH->op1_out;
CH->op1_out = OP_OUT(CH->SLOT[SLOT1],env_out,(CH->op1_out>>CH->FB) ); // +LFOOut[SLOT->AMS]
op_out = (op_out + CH->op1_out)/2;
}
// Original END
/*
// Dave's test II START
if( CH->FB )
{
// with self feed back
op_out = CH->op1_out;
CH->op1_out = OP_OUT(CH->SLOT[SLOT1],env_out,(CH->op1_out*daves_fb_val/100)>>CH->FB);
op_out = (op_out + CH->op1_out)/2;
}
// Dave's test II END
// Dave's test START
if( CH->FB )
{
int i;
int fb;
for (i=0;i<9;i++) daves_fb[i]=daves_fb[i+1];
// with self feed back
fb=0;
fb+=daves_fb[3]/3;
fb+=daves_fb[4];
op_out = OP_OUT(CH->SLOT[SLOT1],env_out,(fb*daves_fb_val/1000)>>CH->FB );
daves_fb[9]=op_out;
// Must end up with a value in op_out
}
// Dave's test END
*/
else
{
// without self feed back
op_out = OP_OUT(CH->SLOT[SLOT1],env_out,0 ); // +LFOOut[SLOT->AMS]
}
// output slot1
if( !CH->connect1 )
{
// algorythm 5
feedback2 = feedback3 = feedback4 = op_out;
}
else
{
// other algorythm
*CH->connect1 += op_out;
}
}
// SLOT 2
env_out=FM_CALC_SLOT(&CH->SLOT[SLOT2]);
if( env_out < EG_ENT-1 )
*CH->connect2 += OP_OUT(CH->SLOT[SLOT2],env_out, feedback2 ); // +LFOOut[SLOT->AMS]
// SLOT 3
env_out=FM_CALC_SLOT(&CH->SLOT[SLOT3]);
if( env_out < EG_ENT-1 )
*CH->connect3 += OP_OUT(CH->SLOT[SLOT3],env_out, feedback3 ); // +LFOOut[SLOT->AMS]
// SLOT 4
env_out=FM_CALC_SLOT(&CH->SLOT[SLOT4]);
if( env_out < EG_ENT-1 )
*CH->connect4 += OP_OUT(CH->SLOT[SLOT4],env_out, feedback4 ); // +LFOOut[SLOT->AMS]
}
/* ---------- frequency counter for operater update ---------- */
INLINE void CALC_FCSLOT(FM_SLOT *SLOT , int fc , int kc )
{
int ksr;
/* frequency step counter */
SLOT->Incr= (fc+SLOT->DT[kc])*SLOT->mul;
ksr = kc >> SLOT->KSR;
if( SLOT->ksr != ksr )
{
SLOT->ksr = ksr;
/* attack , decay rate recalcration */
SLOT->evsa = SLOT->AR[ksr];
SLOT->evsd = SLOT->DR[ksr];
SLOT->evss = SLOT->SR[ksr];
SLOT->evsr = SLOT->RR[ksr];
}
SLOT->TLL = SLOT->TL + KSL[kc];
}
/* ---------- frequency counter ---------- */
INLINE void CALC_FCOUNT(FM_CH *CH )
{
if( CH->SLOT[SLOT1].Incr==-1){
int fc = CH->fc;
int kc = CH->kcode;
CALC_FCSLOT(&CH->SLOT[SLOT1] , fc , kc );
CALC_FCSLOT(&CH->SLOT[SLOT2] , fc , kc );
CALC_FCSLOT(&CH->SLOT[SLOT3] , fc , kc );
CALC_FCSLOT(&CH->SLOT[SLOT4] , fc , kc );
}
}
/* ---------- frequency counter ---------- */
INLINE void OPM_CALC_FCOUNT(YM2151 *OPM , FM_CH *CH )
{
if( CH->SLOT[SLOT1].Incr==-1)
{
int fc = CH->fc;
int kc = CH->kcode;
CALC_FCSLOT(&CH->SLOT[SLOT1] , OPM->KC_TABLE[fc + CH->SLOT[SLOT1].DT2] , kc );
CALC_FCSLOT(&CH->SLOT[SLOT2] , OPM->KC_TABLE[fc + CH->SLOT[SLOT2].DT2] , kc );
CALC_FCSLOT(&CH->SLOT[SLOT3] , OPM->KC_TABLE[fc + CH->SLOT[SLOT3].DT2] , kc );
CALC_FCSLOT(&CH->SLOT[SLOT4] , OPM->KC_TABLE[fc + CH->SLOT[SLOT4].DT2] , kc );
}
}
/* ----------- initialize time tabls ----------- */
static void init_timetables( FM_ST *ST , char *DTTABLE , int ARRATE , int DRRATE )
{
int i,d;
double rate;
/* make detune table */
for (d = 0;d <= 3;d++){
for (i = 0;i <= 31;i++){
rate = (double)DTTABLE[d*32 + i] * ST->freqbase / 4096 * FREQ_RATE;
ST->DT_TABLE[d][i] = rate;
ST->DT_TABLE[d+4][i] = -rate;
}
}
/* make attack rate & decay rate tables */
for (i = 0;i < 4;i++) ST->AR_TABLE[i] = ST->DR_TABLE[i] = 0;
for (i = 4;i < 64;i++){
rate = (double)ST->freqbase / 4096.0; /* frequency rate */
if( i < 60 ) rate *= 1.0+(i&3)*0.25; /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */
rate *= 1<<((i>>2)-1); /* b2-5 : shift bit */
rate *= (double)(EG_ENT<<ENV_BITS);
ST->AR_TABLE[i] = rate / ARRATE;
ST->DR_TABLE[i] = rate / DRRATE;
}
ST->AR_TABLE[62] = EG_AED-1;
ST->AR_TABLE[63] = EG_AED-1;
for (i = 64;i < 94 ;i++){ /* make for overflow area */
ST->AR_TABLE[i] = ST->AR_TABLE[63];
ST->DR_TABLE[i] = ST->DR_TABLE[63];
}
#if 0
for (i = 0;i < 64 ;i++){ /* make for overflow area */
Log(LOG_WAR,"rate %2d , ar %f ms , dr %f ms \n",i,
((double)(EG_ENT<<ENV_BITS) / ST->AR_TABLE[i]) * (1000.0 / ST->rate),
((double)(EG_ENT<<ENV_BITS) / ST->DR_TABLE[i]) * (1000.0 / ST->rate) );
}
#endif
}
/* ---------- reset one of channel ---------- */
static void reset_channel( FM_ST *ST , FM_CH *CH , int chan )
{
int c,s;
ST->mode = 0; /* normal mode */
FM_STATUS_RESET(ST,0xff);
ST->TA = 0;
ST->TAC = 0;
ST->TB = 0;
ST->TBC = 0;
for( c = 0 ; c < chan ; c++ )
{
CH[c].fc = 0;
CH[c].PAN = OPN_CENTER; /* or OPM_CENTER */
for(s = 0 ; s < 4 ; s++ )
{
CH[c].SLOT[s].SEG = 0;
CH[c].SLOT[s].evm = ENV_MOD_OFF;
CH[c].SLOT[s].evc = EG_OFF;
CH[c].SLOT[s].eve = EG_OFF+1;
CH[c].SLOT[s].evs = 0;
}
}
}
/* ---------- generic table initialize ---------- */
static int FMInitTable( void )
{
int s,t;
double rate;
int i,j;
double pom;
/* allocate total level table */
TL_TABLE = malloc(TL_MAX*2*sizeof(int));
if( TL_TABLE == 0 ) return 0;
/* make total level table */
for (t = 0;t < EG_ENT-1 ;t++){
rate = ((1<<TL_BITS)-1)/pow(10,EG_STEP*t/20); /* dB -> voltage */
TL_TABLE[ t] = (int)rate;
TL_TABLE[TL_MAX+t] = -TL_TABLE[t];
/* Log(LOG_INF,"TotalLevel(%3d) = %x\n",t,TL_TABLE[t]);*/
}
/* fill volume off area */
for ( t = EG_ENT-1; t < TL_MAX ;t++){
TL_TABLE[t] = TL_TABLE[TL_MAX+t] = 0;
}
/* make sinwave table (total level offet) */
/* degree 0 = degree 180 = off */
SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2] = &TL_TABLE[EG_ENT-1];
for (s = 1;s <= SIN_ENT/4;s++){
pom = sin(2*PI*s/SIN_ENT); /* sin */
pom = 20*log10(1/pom); /* decibel */
j = pom / EG_STEP; /* TL_TABLE steps */
/* degree 0 - 90 , degree 180 - 90 : plus section */
SIN_TABLE[ s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j];
/* degree 180 - 270 , degree 360 - 270 : minus section */
SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT -s] = &TL_TABLE[TL_MAX+j];
/* Log(LOG_INF,"sin(%3d) = %f:%f db\n",s,pom,(double)j * EG_STEP);*/
}
/* envelope counter -> envelope output table */
for (i=0; i<EG_ENT; i++)
{
/* ATTACK curve */
/* !!!!! preliminary !!!!! */
pom = pow( ((double)(EG_ENT-1-i)/EG_ENT) , 8 ) * EG_ENT;
/* if( pom >= EG_ENT ) pom = EG_ENT-1; */
ENV_CURVE[i] = (int)pom;
/* DECAY ,RELEASE curve */
ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i;
#ifdef SEG_SUPPORT
/* DECAY UPSIDE (SSG ENV) */
ENV_CURVE[(EG_UST>>ENV_BITS)+i]= EG_ENT-1-i;
#endif
}
/* off */
ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1;
/* decay to reattack envelope converttable */
j = EG_ENT-1;
for (i=0; i<EG_ENT; i++)
{
while( j && (ENV_CURVE[j] < i) ) j--;
DRAR_TABLE[i] = j<<ENV_BITS;
/* Log(LOG_INF,"DR %06X = %06X,AR=%06X\n",i,DRAR_TABLE[i],ENV_CURVE[DRAR_TABLE[i]>>ENV_BITS] ); */
}
return 1;
}
static void FMCloseTable( void )
{
if( TL_TABLE ) free( TL_TABLE );
return;
}
/* OPN/OPM Mode Register Write */
INLINE void FMSetMode( FM_ST *ST ,int n,int v )
{
/* b7 = CSM MODE */
/* b6 = 3 slot mode */
/* b5 = reset b */
/* b4 = reset a */
/* b3 = timer enable b */
/* b2 = timer enable a */
/* b1 = load b */
/* b0 = load a */
ST->mode = v;
/* reset Timer b flag */
if( v & 0x20 )
FM_STATUS_RESET(ST,0x02);
/* reset Timer a flag */
if( v & 0x10 )
FM_STATUS_RESET(ST,0x01);
/* load b */
if( v & 0x02 )
{
if( ST->TBC == 0 )
{
ST->TBC = ( 256-ST->TB)<<4;
/* External timer handler */
// if (ST->Timer_Handler) (ST->Timer_Handler)(n,1,(double)ST->TBC,ST->TimerBase);
}
}else if (ST->timermodel == FM_TIMER_INTERVAL)
{ /* stop interbval timer */
if( ST->TBC != 0 )
{
ST->TBC = 0;
// if (ST->Timer_Handler) (ST->Timer_Handler)(n,1,0,ST->TimerBase);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?