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 + -
显示快捷键?