📄 fm.c
字号:
static char OPN_DTTABLE[4 * 32]={
/* this table is YM2151 and YM2612 data */
/* FD=0 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* FD=1 */
0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8,
/* FD=2 */
1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5,
5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16,
/* FD=3 */
2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,
8 , 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22
};
/* multiple table */
#define ML 2
static const int MUL_TABLE[4*16]= {
/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 */
0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML,
8.00*ML, 9.00*ML,10.00*ML,11.00*ML,12.00*ML,13.00*ML,14.00*ML,15.00*ML,
/* DT2=1 *SQL(2) */
0.71*ML, 1.41*ML, 2.82*ML, 4.24*ML, 5.65*ML, 7.07*ML, 8.46*ML, 9.89*ML,
11.30*ML,12.72*ML,14.10*ML,15.55*ML,16.96*ML,18.37*ML,19.78*ML,21.20*ML,
/* DT2=2 *SQL(2.5) */
0.78*ML, 1.57*ML, 3.14*ML, 4.71*ML, 6.28*ML, 7.85*ML, 9.42*ML,10.99*ML,
12.56*ML,14.13*ML,15.70*ML,17.27*ML,18.84*ML,20.41*ML,21.98*ML,23.55*ML,
/* DT2=3 *SQL(3) */
0.87*ML, 1.73*ML, 3.46*ML, 5.19*ML, 6.92*ML, 8.65*ML,10.38*ML,12.11*ML,
13.84*ML,15.57*ML,17.30*ML,19.03*ML,20.76*ML,22.49*ML,24.22*ML,25.95*ML
};
#undef ML
#ifdef LFO_SUPPORT
/* LFO frequency timer table */
static int OPM_LFO_TABLE[256];
#endif
/* dummy attack / decay rate ( when rate == 0 ) */
static int RATE_0[32]=
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
/* -------------------- state --------------------- */
/* some globals */
#define TYPE_SSG 0x01 /* SSG support */
#define TYPE_OPN 0x02 /* OPN device */
#define TYPE_LFOPAN 0x04 /* OPN type LFO and PAN */
#define TYPE_6CH 0x08 /* FM 6CH / 3CH */
#define TYPE_DAC 0x10 /* YM2612's DAC device */
#define TYPE_ADPCM 0x20 /* ADPCM device */
#define TYPE_YM2203 (TYPE_SSG)
#define TYPE_YM2608 (TYPE_SSG |TYPE_LFOPAN |TYPE_6CH |TYPE_ADPCM)
#define TYPE_YM2610 (TYPE_SSG |TYPE_LFOPAN |TYPE_6CH |TYPE_ADPCM)
#define TYPE_YM2612 (TYPE_6CH |TYPE_LFOPAN |TYPE_DAC)
static int FMNumChips; /* total # of FM emulated */
static unsigned char sample_16bit;/* output bits */
/* work table */
static void *cur_chip = 0; /* current chip point */
/* currenct chip state */
static FM_ST *State;
static FMSAMPLE *bufL,*bufR;
static FM_CH *cch[8];
static signed int outd[4];
/* operator connection work */
static int feedback2; /* connect for operator 2 */
static int feedback3; /* connect for operator 3 */
static int feedback4; /* connect for operator 4 */
#ifdef FM_OUTPUT_PROC
static void (* outputproc)( void **buf, int data );
#endif
/* --------------- Customize External interface port (SSG,Timer,etc) ---------------*/
#include "fmext.c"
/* --------------------- subroutines --------------------- */
INLINE int Limit( int val, int max, int min ) {
if ( val > max )
val = max;
else if ( val < min )
val = min;
return val;
}
/* ----- key on ----- */
INLINE void FM_KEYON(FM_CH *CH , int s )
{
FM_SLOT *SLOT = &CH->SLOT[s];
if( SLOT->evm<= ENV_MOD_RR)
{
/* set envelope counter from envleope output */
/* sin wave restart */
SLOT->Cnt = 0;
if( s == SLOT1 ) CH->op1_out = 0;
/* set attack */
#ifdef SEG_SUPPORT
if( SLOT->SEG&8 ) ENV_SSG_AR;
else
#endif
SLOT->evm = ENV_MOD_AR;
SLOT->evs = SLOT->evsa;
#if 0
/* convert decay count to attack count */
/* --- This caused the problem by credit sound of paper boy. --- */
SLOT->evc = EG_AST + DRAR_TABLE[ENV_CURVE[SLOT->evc>>ENV_BITS]];/* + SLOT->evs;*/
#else
/* reset attack counter */
SLOT->evc = EG_AST;
#endif
SLOT->eve = EG_AED;
}
}
/* ----- key off ----- */
INLINE void FM_KEYOFF(FM_CH *CH , int s )
{
FM_SLOT *SLOT = &CH->SLOT[s];
if( SLOT->evm > ENV_MOD_RR)
{
/* set envelope counter from envleope output */
SLOT->evm = ENV_MOD_RR;
if( !(SLOT->evc&EG_DST) )
SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<<ENV_BITS) + EG_DST;
SLOT->eve = EG_DED;
SLOT->evs = SLOT->evsr;
}
}
/* ---------- calcrate Envelope Generator & Phase Generator ---------- */
/* return : envelope output */
INLINE signed int FM_CALC_SLOT( FM_SLOT *SLOT )
{
/* calcrate phage generator */
SLOT->Cnt += SLOT->Incr;
/* calcrate envelope generator */
if( (SLOT->evc+=SLOT->evs) >= SLOT->eve )
{
switch( SLOT->evm ){
case ENV_MOD_AR: /* ATTACK -> DECAY1 */
/* next DR */
SLOT->evm = ENV_MOD_DR;
SLOT->evc = EG_DST;
SLOT->eve = SLOT->SL;
SLOT->evs = SLOT->evsd;
break;
case ENV_MOD_DR: /* DECAY -> SUSTAIN */
SLOT->evm = ENV_MOD_SR;
SLOT->evc = SLOT->SL;
SLOT->eve = EG_DED;
SLOT->evs = SLOT->evss;
break;
case ENV_MOD_RR: /* RR -> OFF & STOP */
SLOT->evm = ENV_MOD_OFF;
case ENV_MOD_SR: /* SR -> OFF & STOP */
SLOT->evc = EG_OFF;
SLOT->eve = EG_OFF+1;
SLOT->evs = 0;
break;
#ifdef SEG_SUPPORT
case ENV_SSG_AR: /* SSG ATTACK */
if( SLOT->SEG&4){ /* start direction */
/* next SSG-SR (upside start ) */
SLOT->evm = ENV_SSG_SR;
SLOT->evc = SLOT->SL + (EG_UST - EG_DST);
SLOT->eve = EG_UED;
SLOT->evs = SLOT->evss;
}else{
/* next SSG-DR (downside start ) */
SLOT->evm = ENV_SSG_DR;
SLOT->evc = EG_DST;
SLOT->eve = EG_DED;
SLOT->evs = SLOT->evsd;
}
break;
case ENV_SSG_DR: /* SEG down side */
if( SLOT->SEG&2){
/* reverce */
SLOT->evm = ENV_SSG_SR;
SLOT->evc = SLOT->SL + (EG_UST - EG_DST);
SLOT->eve = EG_UED;
SLOT->evs = SLOT->evss;
}else{
/* again */
SLOT->evc = EG_DST;
}
/* hold */
if( SLOT->SEG&1) SLOT->evs = 0;
break;
case ENV_SSG_SR: /* upside */
if( SLOT->SEG&2){
/* reverce */
SLOT->evm = ENV_SSG_DR;
SLOT->evc = EG_DST;
SLOT->eve = EG_DED;
SLOT->evs = SLOT->evsd;
}else{
/* again */
SLOT->evc = SLOT->SL + (EG_UST - EG_DST);
}
/* hold check */
if( SLOT->SEG&1) SLOT->evs = 0;
break;
#endif
}
}
/* calcrate envelope */
#if 0 /* ifdef TL_SAVE_MEM */
signed int env_out = SLOT->TLL+ENV_CURVE[SLOT->evc>>ENV_BITS]; /* LFO_out[SLOT->AMS] */
if(env_out >= (EG_ENT-1) ) return EG_ENT-1;
return env_out;
#else
return SLOT->TLL+ENV_CURVE[SLOT->evc>>ENV_BITS]; /* LFO_out[SLOT->AMS] */
#endif
}
/* set algorythm connection */
static void set_algorythm( FM_CH *CH )
{
signed int *carrier = &outd[CH->PAN];
/* setup connect algorythm */
switch( CH->ALGO ){
case 0:
/* PG---S1---S2---S3---S4---OUT */
CH->connect1 = &feedback2;
CH->connect2 = &feedback3;
CH->connect3 = &feedback4;
break;
case 1:
/* PG---S1-+-S3---S4---OUT */
/* PG---S2-+ */
CH->connect1 = &feedback3;
CH->connect2 = &feedback3;
CH->connect3 = &feedback4;
break;
case 2:
/* PG---S1------+-S4---OUT */
/* PG---S2---S3-+ */
CH->connect1 = &feedback4;
CH->connect2 = &feedback3;
CH->connect3 = &feedback4;
break;
case 3:
/* PG---S1---S2-+-S4---OUT */
/* PG---S3------+ */
CH->connect1 = &feedback2;
CH->connect2 = &feedback4;
CH->connect3 = &feedback4;
break;
case 4:
/* PG---S1---S2-+--OUT */
/* PG---S3---S4-+ */
CH->connect1 = &feedback2;
CH->connect2 = carrier;
CH->connect3 = &feedback4;
break;
case 5:
/* +-S2-+ */
/* PG---S1-+-S3-+-OUT */
/* +-S4-+ */
CH->connect1 = 0; /* special mark */
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;
}
/* 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;
/* SLOT 1 */
env_out=FM_CALC_SLOT(&CH->SLOT[SLOT1]);
if( env_out < EG_ENT-1 )
{
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;
}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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -