📄 fm.c
字号:
FM_STATUS_RESET(ST,0xff); } else { /* Set IRQ mask */ /* !!!!!!!!!! pending !!!!!!!!!! */ }}#ifdef YM2608_RHYTHM_PCM/**** RYTHM (PCM) ****/INLINE void YM2608_RYTHM( YM2608 *F2608, ADPCM_CH *ch ){ UINT32 step; ch->now_step += ch->step; if ( ch->now_step >= (1<<ADPCM_SHIFT) ) { step = ch->now_step >> ADPCM_SHIFT; ch->now_step &= (1<<ADPCM_SHIFT)-1; /* end check */ if ( (ch->now_addr+step) > (ch->end<<1) ) { ch->flag = 0; F2608->adpcm_arrivedEndAddress |= ch->flagMask; return; } do{ /* get a next pcm data */ ch->adpcmx = ((short *)pcmbufA)[ch->now_addr]; ch->now_addr++; /**** calc pcm * volume data ****/ ch->adpcml = ch->adpcmx * ch->volume; }while(--step); } /* output for work of output channels (out_ch[OPNxxxx])*/ *(ch->pan) += ch->adpcml;}#endif /* YM2608_RHYTHM_PCM *//* ---------- update one of chip ----------- */void YM2608UpdateOne(int num, INT16 **buffer, int length){ YM2608 *F2608 = &(FM2608[num]); FM_OPN *OPN = &(FM2608[num].OPN); YM_DELTAT *DELTAT = &(F2608[num].deltaT); int i,j; FM_CH *ch; FMSAMPLE *bufL,*bufR; /* setup DELTA-T unit */ YM_DELTAT_DECODE_PRESET(DELTAT); DELTAT->arrivedFlag = 0; /* ASG */ DELTAT->flagMask = 1; /* ASG */ /* set bufer */ bufL = buffer[0]; bufR = buffer[1]; if( (void *)F2608 != cur_chip ){ cur_chip = (void *)F2608; State = &OPN->ST; cch[0] = &F2608->CH[0]; cch[1] = &F2608->CH[1]; cch[2] = &F2608->CH[2]; cch[3] = &F2608->CH[3]; cch[4] = &F2608->CH[4]; cch[5] = &F2608->CH[5]; /* setup adpcm rom address */ pcmbufA = F2608->pcmbuf; pcmsizeA = F2608->pcm_size;#if FM_LFO_SUPPORT LFOCnt = OPN->LFOCnt; LFOIncr = OPN->LFOIncr; if( !LFOIncr ) lfo_amd = lfo_pmd = 0;#endif } /* update frequency counter */ OPN_CALC_FCOUNT( cch[0] ); OPN_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 OPN_CALC_FCOUNT( cch[2] ); OPN_CALC_FCOUNT( cch[3] ); OPN_CALC_FCOUNT( cch[4] ); OPN_CALC_FCOUNT( cch[5] ); /* buffering */ for( i=0; i < length ; i++ ) {#if FM_LFO_SUPPORT /* LFO */ if( LFOIncr ) { lfo_amd = OPN_LFO_wave[(LFOCnt+=LFOIncr)>>LFO_SHIFT]; lfo_pmd = lfo_amd-(LFO_RATE/2); }#endif /* clear output acc. */ out_ch[OUTD_LEFT] = out_ch[OUTD_RIGHT]= out_ch[OUTD_CENTER] = 0; /**** deltaT ADPCM ****/ if( DELTAT->flag ) YM_DELTAT_ADPCM_CALC(DELTAT); /* FM */ for(ch = cch[0] ; ch <= cch[5] ; ch++) FM_CALC_CH( ch ); for( j = 0; j < 6; j++ ) { /**** ADPCM ****/ if( F2608->adpcm[j].flag )#ifdef YM2608_RHYTHM_PCM YM2608_RYTHM(F2608, &F2608->adpcm[j]);#else OPNB_ADPCM_CALC_CHA( F2608, &F2608->adpcm[j]);#endif } /* buffering */ FM_BUFFERING_STEREO; /* timer A controll */ INTERNAL_TIMER_A( State , cch[2] ) } INTERNAL_TIMER_B(State,length) if (DELTAT->arrivedFlag) FM_STATUS_SET(State, 0x04); /* ASG */#if FM_LFO_SUPPORT OPN->LFOCnt = LFOCnt;#endif}/* -------------------------- YM2608(OPNA) ---------------------------------- */int YM2608Init(int num, int clock, int rate, void **pcmrom,int *pcmsize,short *rhythmrom,int *rhythmpos, FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler){ int i,j; if (FM2608) return (-1); /* duplicate init. */ cur_chip = NULL; /* hiro-shi!! */ YM2608NumChips = num; /* allocate extend state space */ if( (FM2608 = (YM2608 *)malloc(sizeof(YM2608) * YM2608NumChips))==NULL) return (-1); /* clear */ memset(FM2608,0,sizeof(YM2608) * YM2608NumChips); /* allocate total level table (128kb space) */ if( !OPNInitTable() ) { free( FM2608 ); return (-1); } for ( i = 0 ; i < YM2608NumChips; i++ ) { FM2608[i].OPN.ST.index = i; FM2608[i].OPN.type = TYPE_YM2608; FM2608[i].OPN.P_CH = FM2608[i].CH; FM2608[i].OPN.ST.clock = clock; FM2608[i].OPN.ST.rate = rate; /* FM2608[i].OPN.ST.irq = 0; */ /* FM2608[i].OPN.ST.status = 0; */ FM2608[i].OPN.ST.timermodel = FM_TIMER_INTERVAL; /* Extend handler */ FM2608[i].OPN.ST.Timer_Handler = TimerHandler; FM2608[i].OPN.ST.IRQ_Handler = IRQHandler; /* DELTA-T */ FM2608[i].deltaT.memory = (UINT8 *)(pcmrom[i]); FM2608[i].deltaT.memory_size = pcmsize[i]; /* ADPCM(Rythm) */ FM2608[i].pcmbuf = (UINT8 *)rhythmrom;#ifdef YM2608_RHYTHM_PCM /* rhythm sound setup (PCM) */ for(j=0;j<6;j++) { /* rhythm sound */ FM2608[i].adpcm[j].start = rhythmpos[j]; FM2608[i].adpcm[j].end = rhythmpos[j+1]-1; } FM2608[i].pcm_size = rhythmpos[6];#else /* rhythm sound setup (ADPCM) */ FM2608[i].pcm_size = rhythmsize;#endif YM2608ResetChip(i); } InitOPNB_ADPCMATable(); return 0;}/* ---------- shut down emurator ----------- */void YM2608Shutdown(){ if (!FM2608) return; FMCloseTable(); free(FM2608); FM2608 = NULL;}/* ---------- reset one of chip ---------- */void YM2608ResetChip(int num){ int i; YM2608 *F2608 = &(FM2608[num]); FM_OPN *OPN = &(FM2608[num].OPN); YM_DELTAT *DELTAT = &(F2608[num].deltaT); /* Reset Priscaler */ OPNSetPris( OPN, 6*24, 6*24,4*2); /* OPN 1/6 , SSG 1/4 */ /* reset SSG section */ SSGReset(OPN->ST.index); /* status clear */ FM_IRQMASK_SET(&OPN->ST,0x1f); OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */ /* extend 3ch. disable */ /*OPN->type &= (~TYPE_6CH); */ reset_channel( &OPN->ST , F2608->CH , 6 ); /* reset OPerator paramater */ 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); /* reset ADPCM unit */ /**** ADPCM work initial ****/ for( i = 0; i < 6+1; i++ ){ F2608->adpcm[i].now_addr = 0; F2608->adpcm[i].now_step = 0; F2608->adpcm[i].step = 0; F2608->adpcm[i].start = 0; F2608->adpcm[i].end = 0; /* F2608->adpcm[i].delta = 21866; */ F2608->adpcm[i].volume = 0; F2608->adpcm[i].pan = &out_ch[OUTD_CENTER]; /* default center */ F2608->adpcm[i].flagMask = (i == 6) ? 0x20 : 0; F2608->adpcm[i].flag = 0; F2608->adpcm[i].adpcmx = 0; F2608->adpcm[i].adpcmd = 127; F2608->adpcm[i].adpcml = 0; } F2608->adpcmTL = &(TL_TABLE[0x3f*(int)(0.75/EG_STEP)]); /* F2608->port1state = -1; */ F2608->adpcm_arrivedEndAddress = 0; /* don't used */ /* DELTA-T unit */ DELTAT->freqbase = OPN->ST.freqbase; DELTAT->output_pointer = out_ch; DELTAT->portshift = 5; /* allways 5bits shift */ /* ASG */ DELTAT->output_range = DELTAT_MIXING_LEVEL<<TL_BITS; YM_DELTAT_ADPCM_Reset(DELTAT,OUTD_CENTER);}/* YM2608 write *//* n = number *//* a = address *//* v = value */int YM2608Write(int n, int a,UINT8 v){ YM2608 *F2608 = &(FM2608[n]); FM_OPN *OPN = &(FM2608[n].OPN); int addr; switch(a&3){ case 0: /* address port 0 */ 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*24, 6*24, 4*2); /* OPN 1/6 , SSG 1/4 */ F2608->deltaT.freqbase = OPN->ST.freqbase; break; case 0x2e: /* divider sel */ OPNSetPris( OPN, 3*24, 3*24,2*2); /* OPN 1/3 , SSG 1/2 */ F2608->deltaT.freqbase = OPN->ST.freqbase; break; case 0x2f: /* divider sel */ OPNSetPris( OPN, 2*24, 2*24,1*2); /* OPN 1/2 , SSG 1/1 */ F2608->deltaT.freqbase = OPN->ST.freqbase; break; } break; case 1: /* data port 0 */ addr = OPN->ST.address; switch(addr & 0xf0) { case 0x00: /* SSG section */ /* Write data to SSG emurator */ SSGWrite(n,a,v); break; case 0x10: /* 0x10-0x1f : Rhythm section */ YM2608UpdateReq(n); FM_ADPCMAWrite(F2608,addr-0x10,v); break; case 0x20: /* Mode Register */ switch(addr) { case 0x29: /* SCH,xirq mask */ /* SCH,xx,xxx,EN_ZERO,EN_BRDY,EN_EOS,EN_TB,EN_TA */ /* extend 3ch. enable/disable */ if(v&0x80) OPN->type |= TYPE_6CH; else OPN->type &= ~TYPE_6CH; /* IRQ MASK */ FM_IRQMASK_SET(&OPN->ST,v&0x1f); break; default: YM2608UpdateReq(n); OPNWriteMode(OPN,addr,v); } break; default: /* OPN section */ YM2608UpdateReq(n); OPNWriteReg(OPN,addr,v); } break; case 2: /* address port 1 */ F2608->address1 = v & 0xff; break; case 3: /* data port 1 */ addr = F2608->address1; YM2608UpdateReq(n); switch( addr & 0xf0 ) { case 0x00: /* ADPCM PORT */ switch( addr ) { case 0x0c: /* Limit address L */ /*F2608->ADLimit = (F2608->ADLimit & 0xff00) | v; */ /*break; */ case 0x0d: /* Limit address H */ /*F2608->ADLimit = (F2608->ADLimit & 0x00ff) | (v<<8); */ /*break; */ case 0x0e: /* DAC data */ /*break; */ case 0x0f: /* PCM data port */ /*F2608->ADData = v; */ /*FM_STATUS_RESET(F2608->OPN.ST,0x08); */ break; default: /* 0x00-0x0b */ YM_DELTAT_ADPCM_Write(&F2608->deltaT,addr,v); } break; case 0x10: /* IRQ Flag controll */ if( addr == 0x10 ) YM2608IRQFlagWrite(&(OPN->ST),n,v); break; default: OPNWriteReg(OPN,addr|0x100,v); } } return OPN->ST.irq;}UINT8 YM2608Read(int n,int a){ YM2608 *F2608 = &(FM2608[n]); int addr = F2608->OPN.ST.address; int ret = 0; switch( a&3 ){ case 0: /* status 0 : YM2203 compatible */ /* BUSY:x:x:x:x:x:FLAGB:FLAGA */ if(addr==0xff) ret = 0x00; /* ID code */ else ret = F2608->OPN.ST.status & 0x83; break; case 1: /* status 0 */ if( addr < 16 ) ret = SSGRead(n); break; case 2: /* status 1 : + ADPCM status */ /* BUSY:x:PCMBUSY:ZERO:BRDY:EOS:FLAGB:FLAGA */ if(addr==0xff) ret = 0x00; /* ID code */ else ret = F2608->OPN.ST.status | (F2608->adpcm[6].flag ? 0x20 : 0); break; case 3: ret = 0; break; } return ret;}int YM2608TimerOver(int n,int c){ YM2608 *F2608 = &(FM2608[n]); if( c ) { /* Timer B */ TimerBOver( &(F2608->OPN.ST) ); } else { /* Timer A */ YM2608UpdateReq(n); /* timer update */ TimerAOver( &(F2608->OPN.ST) ); /* CSM mode key,TL controll */ if( F2608->OPN.ST.mode & 0x80 ) { /* CSM mode total level latch and auto key on */ CSMKeyControll( &(F2608->CH[2]) ); } } return FM2608->OPN.ST.irq;}#endif /* BUILD_YM2608 */#if BUILD_OPNB/* -------------------------- YM2610(OPNB) ---------------------------------- */static YM2610 *FM2610=NULL; /* array of YM2610's */static int YM2610NumChips; /* total chip *//* ---------- update one of chip (YM2610B FM6: ADPCM-A6: ADPCM-B:1) ----------- */void YM2610UpdateOne(int num, INT16 **buffer, int length){ YM2610 *F2610 = &(FM2610[num]); FM_OPN *OPN = &(FM2610[num].OPN); YM_DELTAT *DELTAT = &(F2610[num].deltaT); int i,j; int ch; FMSAMPLE *bufL,*bufR; /* setup DELTA-T unit */ YM_DELTAT_DECODE_PRESET(DELTAT); /* buffer setup */ bufL = buffer[0]; bufR = buffer[1]; if( (void *)F2610 != cur_chip ){ cur_chip = (void *)F2610; State = &OPN->ST; cch[0] = &F2610->CH[1]; cch[1] = &F2610->CH[2]; cch[2] = &F2610->CH[4]; cch[3] = &F2610->CH[5]; /* setup adpcm rom address */ pcmbufA = F2610->pcmbuf; pcmsizeA = F2610->pcm_size;#if FM_LFO_SUPPORT LFOCnt = OPN->LFOCnt; LFOIncr = OPN->LFOIncr; if( !LFOIncr ) lfo_amd = lfo_pmd = 0;#endif }#ifdef YM2610B_WARNING#define FM_MSG_YM2610B "YM2610-%d.CH%d is playing,Check whether the type of the chip is YM2610B\n" /* Check YM2610B worning message *//* if( FM_KEY_IS(&F2610->CH[0].SLOT[3]) ) *//* LOG(LOG_WAR,(FM_MSG_YM2610B,num,0)); *//* if( FM_KEY_IS(&F2610->CH[3].SLOT[3]) ) *//* LOG(LOG_WAR,(FM_MSG_YM2610B,num,3)); */#endi
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -