📄 fmopl.c
字号:
} /* TOP-CY key on/off */ if(rkey&0x02) { if(v&0x02) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT2]); else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2]); } /* HH key on/off */ if(rkey&0x01) { if(v&0x01) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT1]); else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1]); } } } return; } /* keyon,block,fnum */ if( (r&0x0f) > 8) return; CH = &OPL->P_CH[r&0x0f]; if(!(r&0x10)) { /* a0-a8 */ block_fnum = (CH->block_fnum&0x1f00) | v; } else { /* b0-b8 */ int keyon = (v>>5)&1; block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); if(CH->keyon != keyon) { if( (CH->keyon=keyon) ) { CH->op1_out[0] = CH->op1_out[1] = 0; OPL_KEYON(&CH->SLOT[SLOT1]); OPL_KEYON(&CH->SLOT[SLOT2]); } else { OPL_KEYOFF(&CH->SLOT[SLOT1]); OPL_KEYOFF(&CH->SLOT[SLOT2]); } } } /* update */ if(CH->block_fnum != block_fnum) { int blockRv = 7-(block_fnum>>10); int fnum = block_fnum&0x3ff; CH->block_fnum = block_fnum; CH->ksl_base = KSL_TABLE[block_fnum>>6]; CH->fc = OPL->FN_TABLE[fnum]>>blockRv; CH->kcode = CH->block_fnum>>9; if( (OPL->mode&0x40) && CH->block_fnum&0x100) CH->kcode |=1; CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); } return; case 0xc0: /* FB,C */ if( (r&0x0f) > 8) return; CH = &OPL->P_CH[r&0x0f]; { int feedback = (v>>1)&7; CH->FB = feedback ? (8+1) - feedback : 0; CH->CON = v&1; set_algorythm(CH); } return; case 0xe0: /* wave type */ slot = slot_array[r&0x1f]; if(slot == -1) return; CH = &OPL->P_CH[slot/2]; if(OPL->wavesel) { /* LOG(LOG_INF,("OPL SLOT %d wave select %d\n",slot,v&3)); */ CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v&0x03)*SIN_ENT]; } return; }}/* lock/unlock for common table */static int OPL_LockTable(void){ num_lock++; if(num_lock>1) return 0; /* first time */ cur_chip = NULL; /* allocate total level table (128kb space) */ if( !OPLOpenTable() ) { num_lock--; return -1; } return 0;}static void OPL_UnLockTable(void){ if(num_lock) num_lock--; if(num_lock) return; /* last time */ cur_chip = NULL; OPLCloseTable();}#if (BUILD_YM3812 || BUILD_YM3526)/*******************************************************************************//* YM3812 local section *//*******************************************************************************//* ---------- update one of chip ----------- */void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length){ int i; int data; OPLSAMPLE *buf = buffer; UINT32 amsCnt = OPL->amsCnt; UINT32 vibCnt = OPL->vibCnt; UINT8 rythm = OPL->rythm&0x20; OPL_CH *CH,*R_CH; if( (void *)OPL != cur_chip ){ cur_chip = (void *)OPL; /* channel pointers */ S_CH = OPL->P_CH; E_CH = &S_CH[9]; /* rythm slot */ SLOT7_1 = &S_CH[7].SLOT[SLOT1]; SLOT7_2 = &S_CH[7].SLOT[SLOT2]; SLOT8_1 = &S_CH[8].SLOT[SLOT1]; SLOT8_2 = &S_CH[8].SLOT[SLOT2]; /* LFO state */ amsIncr = OPL->amsIncr; vibIncr = OPL->vibIncr; ams_table = OPL->ams_table; vib_table = OPL->vib_table; } R_CH = rythm ? &S_CH[6] : E_CH; for( i=0; i < length ; i++ ) { /* channel A channel B channel C */ /* LFO */ ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT]; vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT]; outd[0] = 0; /* FM part */ for(CH=S_CH ; CH < R_CH ; CH++) OPL_CALC_CH(CH); /* Rythn part */ if(rythm) OPL_CALC_RH(S_CH); /* limit check */ data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT ); /* store to sound buffer */ buf[i] = data >> OPL_OUTSB; } OPL->amsCnt = amsCnt; OPL->vibCnt = vibCnt;#ifdef OPL_OUTPUT_LOG if(opl_dbg_fp) { for(opl_dbg_chip=0;opl_dbg_chip<opl_dbg_maxchip;opl_dbg_chip++) if( opl_dbg_opl[opl_dbg_chip] == OPL) break; fprintf(opl_dbg_fp,"%c%c%c",0x20+opl_dbg_chip,length&0xff,length/256); }#endif}#endif /* (BUILD_YM3812 || BUILD_YM3526) */#if BUILD_Y8950void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length){ int i; int data; OPLSAMPLE *buf = buffer; UINT32 amsCnt = OPL->amsCnt; UINT32 vibCnt = OPL->vibCnt; UINT8 rythm = OPL->rythm&0x20; OPL_CH *CH,*R_CH; YM_DELTAT *DELTAT = OPL->deltat; /* setup DELTA-T unit */ YM_DELTAT_DECODE_PRESET(DELTAT); if( (void *)OPL != cur_chip ){ cur_chip = (void *)OPL; /* channel pointers */ S_CH = OPL->P_CH; E_CH = &S_CH[9]; /* rythm slot */ SLOT7_1 = &S_CH[7].SLOT[SLOT1]; SLOT7_2 = &S_CH[7].SLOT[SLOT2]; SLOT8_1 = &S_CH[8].SLOT[SLOT1]; SLOT8_2 = &S_CH[8].SLOT[SLOT2]; /* LFO state */ amsIncr = OPL->amsIncr; vibIncr = OPL->vibIncr; ams_table = OPL->ams_table; vib_table = OPL->vib_table; } R_CH = rythm ? &S_CH[6] : E_CH; for( i=0; i < length ; i++ ) { /* channel A channel B channel C */ /* LFO */ ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT]; vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT]; outd[0] = 0; /* deltaT ADPCM */ if( DELTAT->portstate ) YM_DELTAT_ADPCM_CALC(DELTAT); /* FM part */ for(CH=S_CH ; CH < R_CH ; CH++) OPL_CALC_CH(CH); /* Rythn part */ if(rythm) OPL_CALC_RH(S_CH); /* limit check */ data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT ); /* store to sound buffer */ buf[i] = data >> OPL_OUTSB; } OPL->amsCnt = amsCnt; OPL->vibCnt = vibCnt; /* deltaT START flag */ if( !DELTAT->portstate ) OPL->status &= 0xfe;}#endif/* ---------- reset one of chip ---------- */void OPLResetChip(FM_OPL *OPL){ int c,s; int i; /* reset chip */ OPL->mode = 0; /* normal mode */ OPL_STATUS_RESET(OPL,0x7f); /* reset with register write */ OPLWriteReg(OPL,0x01,0); /* wabesel disable */ OPLWriteReg(OPL,0x02,0); /* Timer1 */ OPLWriteReg(OPL,0x03,0); /* Timer2 */ OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */ for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0); /* reset OPerator paramater */ for( c = 0 ; c < OPL->max_ch ; c++ ) { OPL_CH *CH = &OPL->P_CH[c]; /* OPL->P_CH[c].PAN = OPN_CENTER; */ for(s = 0 ; s < 2 ; s++ ) { /* wave table */ CH->SLOT[s].wavetable = &SIN_TABLE[0]; /* CH->SLOT[s].evm = ENV_MOD_RR; */ CH->SLOT[s].evc = EG_OFF; CH->SLOT[s].eve = EG_OFF+1; CH->SLOT[s].evs = 0; } }#if BUILD_Y8950 if(OPL->type&OPL_TYPE_ADPCM) { YM_DELTAT *DELTAT = OPL->deltat; DELTAT->freqbase = OPL->freqbase; DELTAT->output_pointer = outd; DELTAT->portshift = 5; DELTAT->output_range = DELTAT_MIXING_LEVEL<<TL_BITS; YM_DELTAT_ADPCM_Reset(DELTAT,0); }#endif}/* ---------- Create one of vietual YM3812 ---------- *//* 'rate' is sampling rate and 'bufsiz' is the size of the */FM_OPL *OPLCreate(int type, int clock, int rate){ char *ptr; FM_OPL *OPL; int state_size; int max_ch = 9; /* normaly 9 channels */ if( OPL_LockTable() ==-1) return NULL; /* allocate OPL state space */ state_size = sizeof(FM_OPL); state_size += sizeof(OPL_CH)*max_ch;#if BUILD_Y8950 if(type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT);#endif /* allocate memory block */ ptr = malloc(state_size); if(ptr==NULL) return NULL; /* clear */ memset(ptr,0,state_size); OPL = (FM_OPL *)ptr; ptr+=sizeof(FM_OPL); OPL->P_CH = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch;#if BUILD_Y8950 if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT);#endif /* set channel state pointer */ OPL->type = type; OPL->clock = clock; OPL->rate = rate; OPL->max_ch = max_ch; /* init grobal tables */ OPL_initalize(OPL); /* reset chip */ OPLResetChip(OPL);#ifdef OPL_OUTPUT_LOG if(!opl_dbg_fp) { opl_dbg_fp = fopen("opllog.opl","wb"); opl_dbg_maxchip = 0; } if(opl_dbg_fp) { opl_dbg_opl[opl_dbg_maxchip] = OPL; fprintf(opl_dbg_fp,"%c%c%c%c%c%c",0x00+opl_dbg_maxchip, type, clock&0xff, (clock/0x100)&0xff, (clock/0x10000)&0xff, (clock/0x1000000)&0xff); opl_dbg_maxchip++; }#endif return OPL;}/* ---------- Destroy one of vietual YM3812 ---------- */void OPLDestroy(FM_OPL *OPL){#ifdef OPL_OUTPUT_LOG if(opl_dbg_fp) { fclose(opl_dbg_fp); opl_dbg_fp = NULL; }#endif OPL_UnLockTable(); free(OPL);}/* ---------- Option handlers ---------- */void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset){ OPL->TimerHandler = TimerHandler; OPL->TimerParam = channelOffset;}void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param){ OPL->IRQHandler = IRQHandler; OPL->IRQParam = param;}void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param){ OPL->UpdateHandler = UpdateHandler; OPL->UpdateParam = param;}#if BUILD_Y8950void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param){ OPL->porthandler_w = PortHandler_w; OPL->porthandler_r = PortHandler_r; OPL->port_param = param;}void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param){ OPL->keyboardhandler_w = KeyboardHandler_w; OPL->keyboardhandler_r = KeyboardHandler_r; OPL->keyboard_param = param;}#endif/* ---------- YM3812 I/O interface ---------- */int OPLWrite(FM_OPL *OPL,int a,int v){ if( !(a&1) ) { /* address port */ OPL->address = v & 0xff; } else { /* data port */ if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);#ifdef OPL_OUTPUT_LOG if(opl_dbg_fp) { for(opl_dbg_chip=0;opl_dbg_chip<opl_dbg_maxchip;opl_dbg_chip++) if( opl_dbg_opl[opl_dbg_chip] == OPL) break; fprintf(opl_dbg_fp,"%c%c%c",0x10+opl_dbg_chip,OPL->address,v); }#endif OPLWriteReg(OPL,OPL->address,v); } return OPL->status>>7;}unsigned char OPLRead(FM_OPL *OPL,int a){ if( !(a&1) ) { /* status port */ return OPL->status & (OPL->statusmask|0x80); } /* data port */ switch(OPL->address) { case 0x05: /* KeyBoard IN */ if(OPL->type&OPL_TYPE_KEYBOARD) { if(OPL->keyboardhandler_r) return OPL->keyboardhandler_r(OPL->keyboard_param); else LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n")); } return 0;#if 0 case 0x0f: /* ADPCM-DATA */ return 0;#endif case 0x19: /* I/O DATA */ if(OPL->type&OPL_TYPE_IO) { if(OPL->porthandler_r) return OPL->porthandler_r(OPL->port_param); else LOG(LOG_WAR,("OPL:read unmapped I/O port\n")); } return 0; case 0x1a: /* PCM-DATA */ return 0; } return 0;}int OPLTimerOver(FM_OPL *OPL,int c){ if( c ) { /* Timer B */ OPL_STATUS_SET(OPL,0x20); } else { /* Timer A */ OPL_STATUS_SET(OPL,0x40); /* CSM mode key,TL controll */ if( OPL->mode & 0x80 ) { /* CSM mode total level latch and auto key on */ int ch; if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); for(ch=0;ch<9;ch++) CSMKeyControll( &OPL->P_CH[ch] ); } } /* reload timer */ if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase); return OPL->status>>7;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -