fm.c

来自「DGen源码最后版本」· C语言 代码 · 共 2,003 行 · 第 1/5 页

C
2,003
字号
    free(FM2203);
    FM2203 = NULL;
}

/* ---------- YM2203 I/O interface ---------- */
int YM2203Write(int n,int a,int v)
{
    FM_OPN *OPN = &(FM2203[n].OPN);

    if( !(a&1) )
    {   /* address port */
        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*12, 6*12 ,4); /* OPN 1/6 , SSG 1/4 */
            break;
        case 0x2e:  /* divider sel */
            OPNSetPris( OPN, 3*12, 3*12,2); /* OPN 1/3 , SSG 1/2 */
            break;
        case 0x2f:  /* divider sel */
            OPNSetPris( OPN, 2*12, 2*12,1); /* OPN 1/2 , SSG 1/1 */
            break;
        }
    }
    else
    {   /* data port */
        int addr = OPN->ST.address;
        switch( addr & 0xf0 )
        {
        case 0x00:  /* 0x00-0x0f : SSG section */
            /* Write data to SSG emurator */
            //SSGWrite(n,a,v);
            break;
        case 0x20:  /* 0x20-0x2f : Mode section */
            //YM2203UpdateReq(n);
            /* write register */
             OPNWriteMode(OPN,addr,v);
            break;
        default:    /* 0x30-0xff : OPN section */
            //YM2203UpdateReq(n);
            /* write register */
             OPNWriteReg(OPN,addr,v);
        }
    }
    return OPN->ST.irq;
}

unsigned char YM2203Read(int n,int a)
{
    YM2203 *F2203 = &(FM2203[n]);
    int addr = F2203->OPN.ST.address;
    int ret = 0;

    if( !(a&1) )
    {   /* status port */
        ret = F2203->OPN.ST.status;
    }
    else
    {   /* data port (ONLY SSG) */
        //if( addr < 16 ) ret = SSGRead(n);
    }
    return ret;
}

int YM2203TimerOver(int n,int c)
{
    YM2203 *F2203 = &(FM2203[n]);

    if( c )
    {   /* Timer B */
        TimerBOver( &(F2203->OPN.ST) );
    }
    else
    {   /* Timer A */
        //YM2203UpdateReq(n);
        /* timer update */
        TimerAOver( &(F2203->OPN.ST) );
        /* CSM mode key,TL controll */
        if( F2203->OPN.ST.mode & 0x80 )
        {   /* CSM mode total level latch and auto key on */
            CSMKeyControll( &(F2203->CH[2]) );
        }
    }
    return F2203->OPN.ST.irq;
}

#endif /* BUILD_YM2203 */




// Dave:
int fm_chan_on=0xffff; // just to make sure :)

#if BUILD_YM2612
/*******************************************************************************/
/*      YM2612 local section                                                   */
/*******************************************************************************/
static YM2612 *FM2612=NULL; /* array of YM2612's */

/* ---------- update one of chip ----------- */
void YM2612UpdateOne(int num, void **buffer, int length)
{
    YM2612 *F2612 = &(FM2612[num]);
    FM_OPN *OPN   = &(FM2612[num].OPN);
    int dataR,dataL;
    int i,ch;
    int dacen = F2612->dacen;
    int dacout  = F2612->dacout;
    signed short *davel,*daver; // dave

    /* set bufer */
    bufL = (FMSAMPLE *)buffer[0];
    bufR = (FMSAMPLE *)buffer[1];

    davel=(signed short *)buffer[0];
    daver=(signed short *)buffer[1];

    if( (void *)F2612 != cur_chip ){
        cur_chip = (void *)F2612;

        State = &OPN->ST;
        cch[0]   = &F2612->CH[0];
        cch[1]   = &F2612->CH[1];
        cch[2]   = &F2612->CH[2];
        cch[3]   = &F2612->CH[3];
        cch[4]   = &F2612->CH[4];
        cch[5]   = &F2612->CH[5];
    }
    /* update frequency counter */
    CALC_FCOUNT( cch[0] );
    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 CALC_FCOUNT( cch[2] );
    CALC_FCOUNT( cch[3] );
    CALC_FCOUNT( cch[4] );
    CALC_FCOUNT( cch[5] );
    /* buffering */
    for( i=0; i < length ; i++ )
    {
        /* clear output acc. */
        outd[OPN_LEFT] = outd[OPN_RIGHT]= outd[OPN_CENTER] = 0;
        /* calcrate channel output */
//        for( ch=0;ch<5;ch++) FM_CALC_CH( cch[ch] );
// Dave:
        for( ch=0;ch<5;ch++) if (fm_chan_on&(1<<ch)) FM_CALC_CH( cch[ch] );

        dacout=0; // dave temporary
// Dave:
        if (fm_chan_on&(1<<5))
        {
          if( dacen )  *cch[5]->connect4 += dacout;
          else         FM_CALC_CH( cch[5] );
        }

        /* get left & right output */
        dataL = Limit( outd[OPN_CENTER] + outd[OPN_LEFT], OPN_MAXOUT, OPN_MINOUT );
        dataR = Limit( outd[OPN_CENTER] + outd[OPN_RIGHT], OPN_MAXOUT, OPN_MINOUT );

        /* buffering */
#ifdef FM_STEREO_MIX        /* stereo mixing */
        /* stereo mix */
        ((FMSAMPLE_MIX *)bufL)[i] += ((dataL>>OPN_OUTSB)<<FM_OUTPUT_BIT)|(dataR>>OPN_OUTSB);
#else
        /* stereo separate */
        {
          // Dave - write to signed short and clip
          int t;
          t=*davel; t+=(dataL*3)>>(OPN_OUTSB+1);
          if (t>0x7fff) t=0x7fff; if (t<-0x8000) t=-0x8000;
          *davel=t; davel++;

          t=*daver; t+=(dataR*3)>>(OPN_OUTSB+1);
          if (t>0x7fff) t=0x7fff; if (t<-0x8000) t=-0x8000;
          *daver=t; daver++;
        }
#endif

#ifdef LFO_SUPPORT
        CALC_LOPM_LFO;
#endif
#ifdef INTERNAL_TIMER
        /* timer controll */
        CALC_TIMER_A( State , cch[2] );
#endif
    }
#ifdef INTERNAL_TIMER
    CALC_TIMER_B( State , length );
#endif
}

/* -------------------------- YM2612 ---------------------------------- */
int YM2612Init(int num, int clock, int rate,
               FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler)
{
    int i,j;

    if (FM2612) return (-1);    /* duplicate init. */
    cur_chip = NULL;    /* hiro-shi!! */

    FMNumChips = num;

    /* allocate extend state space */
    if( (FM2612 = (YM2612 *)malloc(sizeof(YM2612) * FMNumChips))==NULL)
        return (-1);
    /* clear */
    memset(FM2612,0,sizeof(YM2612) * FMNumChips);
    /* allocate total level table (128kb space) */
    if( !FMInitTable() )
    {
        free( FM2612 );
        return (-1);
    }

    for ( i = 0 ; i < FMNumChips; i++ ) {
        FM2612[i].OPN.ST.index = i;
        FM2612[i].OPN.type = TYPE_YM2612;
        FM2612[i].OPN.P_CH = FM2612[i].CH;
        FM2612[i].OPN.ST.clock = clock;
// Dave fiddling:
        FM2612[i].OPN.ST.rate = rate<<(i-1);
        /* FM2612[i].OPN.ST.irq = 0; */
        /* FM2612[i].OPN.ST.status = 0; */
        FM2612[i].OPN.ST.timermodel = FM_TIMER_SINGLE;
        /* Extend handler */
        FM2612[i].OPN.ST.Timer_Handler = TimerHandler;
        FM2612[i].OPN.ST.IRQ_Handler   = IRQHandler;
        YM2612ResetChip(i);
    }
    return 0;
}

/* ---------- shut down emurator ----------- */
void YM2612Shutdown()
{
    if (!FM2612) return;

    FMCloseTable();
    free(FM2612);
    FM2612 = NULL;
}

/* ---------- reset one of chip ---------- */
void YM2612ResetChip(int num)
{
    int i;
    YM2612 *F2612 = &(FM2612[num]);
    FM_OPN *OPN   = &(FM2612[num].OPN);

    OPNSetPris( OPN , 12*12, 12*12, 0);
    /* status clear */
    FM_IRQMASK_SET(&OPN->ST,0x03);
    OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */

    reset_channel( &OPN->ST , &F2612->CH[0] , 6 );

    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);
    /* DAC mode clear */
    F2612->dacen = 0;
}

/* YM2612 write */
/* n = number  */
/* a = address */
/* v = value   */
int YM2612Write(int n, int a,int v)
{
    YM2612 *F2612 = &(FM2612[n]);
    int addr;

    switch( a&3){
    case 0: /* address port 0 */
        F2612->OPN.ST.address = v & 0xff;
        break;
    case 1: /* data port 0    */
        addr = F2612->OPN.ST.address;
        switch( addr & 0xf0 )
        {
        case 0x20:  /* 0x20-0x2f Mode */
            switch( addr )
            {
            case 0x2a:  /* DAC data (YM2612) */
                //YM2612UpdateReq(n);
                F2612->dacout = v<<(TL_BITS-8);
//                {
//                  extern int mega_dacout;
//                  mega_dacout=v;
//                }

            case 0x2b:  /* DAC Sel  (YM2612) */
                /* b7 = dac enable */
                F2612->dacen = v & 0x80;
//                {
//                  extern int mega_dacen;
//                  mega_dacen=v&0x80;
//                }

                break;

            default:    /* OPN section */
                //YM2612UpdateReq(n);
                /* write register */
                 OPNWriteMode(&(F2612->OPN),addr,v);
            }
            break;
        default:    /* 0x30-0xff OPN section */
            //YM2612UpdateReq(n);
            /* write register */
             OPNWriteReg(&(F2612->OPN),addr,v);
        }
        break;
    case 2: /* address port 1 */
        F2612->address1 = v & 0xff;
        break;
    case 3: /* data port 1    */
        addr = F2612->address1;
        //YM2612UpdateReq(n);
        OPNWriteReg(&(F2612->OPN),addr|0x100,v);
        break;
    }
    return F2612->OPN.ST.irq;
}
unsigned char YM2612Read(int n,int a)
{
    YM2612 *F2612 = &(FM2612[n]);
    int addr = F2612->OPN.ST.address;

    switch( a&3){
    case 0: /* status 0 */
        return F2612->OPN.ST.status;
    case 1:
    case 2:
    case 3:
        Log(LOG_WAR,"YM2612 #%d:A=%d read unmapped area\n");
        return F2612->OPN.ST.status;
    }
    return 0;
}

int YM2612TimerOver(int n,int c)
{
    YM2612 *F2612 = &(FM2612[n]);

    if( c )
    {   /* Timer B */
        TimerBOver( &(F2612->OPN.ST) );
    }
    else
    {   /* Timer A */
        //YM2612UpdateReq(n);
        /* timer update */
        TimerAOver( &(F2612->OPN.ST) );
        /* CSM mode key,TL controll */
        if( F2612->OPN.ST.mode & 0x80 )
        {   /* CSM mode total level latch and auto key on */
            CSMKeyControll( &(F2612->CH[2]) );
        }
    }
    return F2612->OPN.ST.irq;
}

#if 0
/* ---------- set buffer ---------- */
int YM2612SetBuffer(int n, FMSAMPLE **buf )
{
    int i;
    for( i = 0 ; i < YM2612_NUMBUF ; i++){
        FM2612[n].Buf[i] = buf[i];
        if( cur_chip == &FM2612[n] ) cur_chip = NULL;
    }
    return 0;
}
#endif

#endif /* BUILD_YM2612 */


⌨️ 快捷键说明

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