📄 s_fmopl.c
字号:
else SLOT->Cnt += SLOT->Incr; /* connectoion */ outd += OP_OUT(SLOT,env_out, feedback2); }}/* ----------- initialize time tabls ----------- */static void init_timetables( FM_OPL *OPL , int ARRATE , int DRRATE ){ int i; double rate; /* make attack rate & decay rate tables */ for (i = 0;i < 4;i++) OPL->AR_TABLE[i] = OPL->DR_TABLE[i] = 0; for (i = 4;i <= 60;i++){ rate = OPL->freqbase; /* 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); OPL->AR_TABLE[i] = (s32)(rate / ARRATE); OPL->DR_TABLE[i] = (s32)(rate / DRRATE); } for (i = 60;i < 76;i++) { OPL->AR_TABLE[i] = EG_AED-1; OPL->DR_TABLE[i] = OPL->DR_TABLE[60]; }}/* ---------- generic table initialize ---------- */static int OPLOpenTable( void ){ int s,t; double rate; int i,j; double pom; /* allocate dynamic tables */ if( (TL_TABLE = malloc(TL_MAX*2*sizeof(s32))) == NULL) return 0; if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(s32 *))) == NULL) { free(TL_TABLE); return 0; } if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(s32))) == NULL) { free(TL_TABLE); free(SIN_TABLE); return 0; } if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(s32))) == NULL) { free(TL_TABLE); free(SIN_TABLE); free(AMS_TABLE); 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]; } /* 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 = (int)(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]; } for (s = 0;s < SIN_ENT;s++) { SIN_TABLE[SIN_ENT*1+s] = s<(SIN_ENT/2) ? SIN_TABLE[s] : &TL_TABLE[EG_ENT]; SIN_TABLE[SIN_ENT*2+s] = SIN_TABLE[s % (SIN_ENT/2)]; SIN_TABLE[SIN_ENT*3+s] = (s/(SIN_ENT/4))&1 ? &TL_TABLE[EG_ENT] : SIN_TABLE[SIN_ENT*2+s]; } /* envelope counter -> envelope output table */ for (i=0; i<EG_ENT; i++) { /* ATTACK curve */ 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; } /* off */ ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1; /* make LFO ams table */ for (i=0; i<AMS_ENT; i++) { pom = (1.0+sin(2*PI*i/AMS_ENT))/2; /* sin */ AMS_TABLE[i] = (s32)((1.0/EG_STEP)*pom); /* 1dB */ AMS_TABLE[AMS_ENT+i] = (s32)((4.8/EG_STEP)*pom); /* 4.8dB */ } /* make LFO vibrate table */ for (i=0; i<VIB_ENT; i++) { /* 100cent = 1seminote = 6% ?? */ pom = (double)VIB_RATE*0.06*sin(2*PI*i/VIB_ENT); /* +-100sect step */ VIB_TABLE[i] = (s32)(VIB_RATE + (pom*0.07)); /* +- 7cent */ VIB_TABLE[VIB_ENT+i] = (s32)(VIB_RATE + (pom*0.14)); /* +-14cent */ } return 1;}static void OPLCloseTable( void ){ free(TL_TABLE); free(SIN_TABLE); free(AMS_TABLE); free(VIB_TABLE);}/* CSM Key Controll */INLINE void CSMKeyControll(OPL_CH *CH){ OPL_SLOT *slot1 = &CH->SLOT[SLOT1]; OPL_SLOT *slot2 = &CH->SLOT[SLOT2]; /* all key off */ OPL_KEYOFF(slot1); OPL_KEYOFF(slot2); /* total level latch */ slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl); slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl); /* key on */ CH->op1_out[0] = CH->op1_out[1] = 0; OPL_KEYON(slot1); OPL_KEYON(slot2);}/* ---------- opl initialize ---------- */static void OPL_initalize(FM_OPL *OPL){ int fn; /* frequency base */ OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / OPL->rate) / 72 : 0; /* make time tables */ init_timetables( OPL , OPL_ARRATE , OPL_DRRATE ); /* make fnumber -> increment counter table */ for( fn=0 ; fn < 1024 ; fn++ ) { OPL->FN_TABLE[fn] = (u32)(OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2); } /* LFO freq.table */ OPL->amsIncr = (u32)(OPL->rate ? (double)AMS_ENT*(1<<AMS_SHIFT) / OPL->rate * 3.7 * ((double)OPL->clock/3600000) : 0); OPL->vibIncr = (u32)(OPL->rate ? (double)VIB_ENT*(1<<VIB_SHIFT) / OPL->rate * 6.4 * ((double)OPL->clock/3600000) : 0);}/* ---------- write a OPL registers ---------- */static void OPLWriteReg(FM_OPL *OPL, int r, int v){ OPL_CH *CH; int slot; int block_fnum; switch(r&0xe0) { case 0x00: /* 00-1f:controll */ switch(r&0x1f) { case 0x01: OPL->wavesel = v&0x20; if(!OPL->wavesel) { /* preset compatible mode */ int c; for(c=0;c<OPL->max_ch;c++) { OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0]; OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0]; } } return;
} break; case 0x20: /* am,vib,ksr,eg type,mul */ slot = slot_array[r&0x1f]; if(slot == -1) return; set_mul(OPL,slot,v); return; case 0x40: slot = slot_array[r&0x1f]; if(slot == -1) return; set_ksl_tl(OPL,slot,v); return; case 0x60: slot = slot_array[r&0x1f]; if(slot == -1) return; set_ar_dr(OPL,slot,v); return; case 0x80: slot = slot_array[r&0x1f]; if(slot == -1) return; set_sl_rr(OPL,slot,v); return; case 0xa0: switch(r) { case 0xbd: /* amsep,vibdep,r,bd,sd,tom,tc,hh */ { OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0]; OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0]; OPL->rythm = v&0x3f;
} 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((unsigned)CH->block_fnum != (unsigned)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 = (u8)(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) { 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();}/*******************************************************************************//* YM3812 local section *//*******************************************************************************//* ---------- update one of chip ----------- */void YM3812UpdateOne(FM_OPL *OPL, s16 *buffer, int length){ int i; s16 *buf = buffer; u32 amsCnt = OPL->amsCnt; u32 vibCnt = OPL->vibCnt; 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[6]; /* LFO state */ amsIncr = OPL->amsIncr; vibIncr = OPL->vibIncr; ams_table = OPL->ams_table; vib_table = OPL->vib_table; } R_CH = 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; /* FM part */ for(CH=S_CH ; CH < R_CH ; CH++) OPL_CALC_CH(CH); /* store to sound buffer */ buf[i] += (s16)((outd >> OPL_OUTSB) / 56); } OPL->amsCnt = amsCnt; OPL->vibCnt = vibCnt;}/* ---------- 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 */ 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; } }}/* ---------- Create one of vietual YM3812 ---------- *//* 'rate' is sampling rate and 'bufsiz' is the size of the */FM_OPL *OPLCreate(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;
/* 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;
/* set channel state pointer */ OPL->clock = clock; OPL->rate = rate; OPL->max_ch = max_ch; /* init grobal tables */ OPL_initalize(OPL); /* reset chip */ OPLResetChip(OPL); return OPL;}/* ---------- Destroy one of vietual YM3812 ---------- */void OPLDestroy(FM_OPL *OPL){ OPL_UnLockTable(); free(OPL);}/* ---------- 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); OPLWriteReg(OPL,OPL->address,v); } return OPL->status>>7;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -