📄 fmopl.c
字号:
{ /* PG */ if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); else SLOT->Cnt += SLOT->Incr; /* connectoion */ if(CH->FB) { int feedback1 = (CH->op1_out[0]+CH->op1_out[1])>>CH->FB; CH->op1_out[1] = CH->op1_out[0]; *CH->connect1 += CH->op1_out[0] = OP_OUT(SLOT,env_out,feedback1); } else { *CH->connect1 += OP_OUT(SLOT,env_out,0); } }else { CH->op1_out[1] = CH->op1_out[0]; CH->op1_out[0] = 0; } /* SLOT 2 */ SLOT = &CH->SLOT[SLOT2]; env_out=OPL_CALC_SLOT(SLOT); if( env_out < EG_ENT-1 ) { /* PG */ if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); else SLOT->Cnt += SLOT->Incr; /* connectoion */ outd[0] += OP_OUT(SLOT,env_out, feedback2); }}/* ---------- calcrate rythm block ---------- */#define WHITE_NOISE_db 6.0INLINE void OPL_CALC_RH( OPL_CH *CH ){ UINT32 env_tam,env_sd,env_top,env_hh; int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP); INT32 tone8; OPL_SLOT *SLOT; int env_out; /* BD : same as FM serial mode and output level is large */ feedback2 = 0; /* SLOT 1 */ SLOT = &CH[6].SLOT[SLOT1]; env_out=OPL_CALC_SLOT(SLOT); if( env_out < EG_ENT-1 ) { /* PG */ if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); else SLOT->Cnt += SLOT->Incr; /* connectoion */ if(CH[6].FB) { int feedback1 = (CH[6].op1_out[0]+CH[6].op1_out[1])>>CH[6].FB; CH[6].op1_out[1] = CH[6].op1_out[0]; feedback2 = CH[6].op1_out[0] = OP_OUT(SLOT,env_out,feedback1); } else { feedback2 = OP_OUT(SLOT,env_out,0); } }else { feedback2 = 0; CH[6].op1_out[1] = CH[6].op1_out[0]; CH[6].op1_out[0] = 0; } /* SLOT 2 */ SLOT = &CH[6].SLOT[SLOT2]; env_out=OPL_CALC_SLOT(SLOT); if( env_out < EG_ENT-1 ) { /* PG */ if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); else SLOT->Cnt += SLOT->Incr; /* connectoion */ outd[0] += OP_OUT(SLOT,env_out, feedback2)*2; } // SD (17) = mul14[fnum7] + white noise // TAM (15) = mul15[fnum8] // TOP (18) = fnum6(mul18[fnum8]+whitenoise) // HH (14) = fnum7(mul18[fnum8]+whitenoise) + white noise env_sd =OPL_CALC_SLOT(SLOT7_2) + whitenoise; env_tam=OPL_CALC_SLOT(SLOT8_1); env_top=OPL_CALC_SLOT(SLOT8_2); env_hh =OPL_CALC_SLOT(SLOT7_1) + whitenoise; /* PG */ if(SLOT7_1->vib) SLOT7_1->Cnt += (2*SLOT7_1->Incr*vib/VIB_RATE); else SLOT7_1->Cnt += 2*SLOT7_1->Incr; if(SLOT7_2->vib) SLOT7_2->Cnt += ((CH[7].fc*8)*vib/VIB_RATE); else SLOT7_2->Cnt += (CH[7].fc*8); if(SLOT8_1->vib) SLOT8_1->Cnt += (SLOT8_1->Incr*vib/VIB_RATE); else SLOT8_1->Cnt += SLOT8_1->Incr; if(SLOT8_2->vib) SLOT8_2->Cnt += ((CH[8].fc*48)*vib/VIB_RATE); else SLOT8_2->Cnt += (CH[8].fc*48); tone8 = OP_OUT(SLOT8_2,whitenoise,0 ); /* SD */ if( env_sd < EG_ENT-1 ) outd[0] += OP_OUT(SLOT7_1,env_sd, 0)*8; /* TAM */ if( env_tam < EG_ENT-1 ) outd[0] += OP_OUT(SLOT8_1,env_tam, 0)*2; /* TOP-CY */ if( env_top < EG_ENT-1 ) outd[0] += OP_OUT(SLOT7_2,env_top,tone8)*2; /* HH */ if( env_hh < EG_ENT-1 ) outd[0] += OP_OUT(SLOT7_2,env_hh,tone8)*2;}/* ----------- 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] = rate / ARRATE; OPL->DR_TABLE[i] = rate / DRRATE; } for (i = 60;i < 76;i++) { OPL->AR_TABLE[i] = EG_AED-1; OPL->DR_TABLE[i] = OPL->DR_TABLE[60]; }#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) / OPL->AR_TABLE[i]) * (1000.0 / OPL->rate), ((double)(EG_ENT<<ENV_BITS) / OPL->DR_TABLE[i]) * (1000.0 / OPL->rate) )); }#endif}/* ---------- 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(INT32))) == NULL) return 0; if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL) { free(TL_TABLE); return 0; } if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL) { free(TL_TABLE); free(SIN_TABLE); return 0; } if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == 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];/* 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));*/ } 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] = (1.0/EG_STEP)*pom; /* 1dB */ AMS_TABLE[AMS_ENT+i] = (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] = VIB_RATE + (pom*0.07); /* +- 7cent */ VIB_TABLE[VIB_ENT+i] = VIB_RATE + (pom*0.14); /* +-14cent */ /* LOG(LOG_INF,("vib %d=%d\n",i,VIB_TABLE[VIB_ENT+i])); */ } 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; /* Timer base time */ OPL->TimerBase = 1.0/((double)OPL->clock / 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] = OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2; } /* LFO freq.table */ OPL->amsIncr = OPL->rate ? (double)AMS_ENT*(1<<AMS_SHIFT) / OPL->rate * 3.7 * ((double)OPL->clock/3600000) : 0; OPL->vibIncr = 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: /* wave selector enable */ if(OPL->type&OPL_TYPE_WAVESEL) { 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; case 0x02: /* Timer 1 */ OPL->T[0] = (256-v)*4; break; case 0x03: /* Timer 2 */ OPL->T[1] = (256-v)*16; return; case 0x04: /* IRQ clear / mask and Timer enable */ if(v&0x80) { /* IRQ flag clear */ OPL_STATUS_RESET(OPL,0x7f); } else { /* set IRQ mask ,timer enable*/ UINT8 st1 = v&1; UINT8 st2 = (v>>1)&1; /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */ OPL_STATUS_RESET(OPL,v&0x78); OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01); /* timer 2 */ if(OPL->st[1] != st2) { double interval = st2 ? (double)OPL->T[1]*OPL->TimerBase : 0.0; OPL->st[1] = st2; if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval); } /* timer 1 */ if(OPL->st[0] != st1) { double interval = st1 ? (double)OPL->T[0]*OPL->TimerBase : 0.0; OPL->st[0] = st1; if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval); } } return;#if BUILD_Y8950 case 0x06: /* Key Board OUT */ if(OPL->type&OPL_TYPE_KEYBOARD) { if(OPL->keyboardhandler_w) OPL->keyboardhandler_w(OPL->keyboard_param,v); else LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n")); } return; case 0x07: /* DELTA-T controll : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */ if(OPL->type&OPL_TYPE_ADPCM) YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); return; case 0x08: /* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ OPL->mode = v; v&=0x1f; /* for DELTA-T unit */ case 0x09: /* START ADD */ case 0x0a: case 0x0b: /* STOP ADD */ case 0x0c: case 0x0d: /* PRESCALE */ case 0x0e: case 0x0f: /* ADPCM data */ case 0x10: /* DELTA-N */ case 0x11: /* DELTA-N */ case 0x12: /* EG-CTRL */ if(OPL->type&OPL_TYPE_ADPCM) YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); return;#if 0 case 0x15: /* DAC data */ case 0x16: case 0x17: /* SHIFT */ return; case 0x18: /* I/O CTRL (Direction) */ if(OPL->type&OPL_TYPE_IO) OPL->portDirection = v&0x0f; return; case 0x19: /* I/O DATA */ if(OPL->type&OPL_TYPE_IO) { OPL->portLatch = v; if(OPL->porthandler_w) OPL->porthandler_w(OPL->port_param,v&OPL->portDirection); } return; case 0x1a: /* PCM data */ return;#endif#endif } 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 */ { UINT8 rkey = OPL->rythm^v; OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0]; OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0]; OPL->rythm = v&0x3f; if(OPL->rythm&0x20) {#if 0 usrintf_showmessage("OPL Rythm mode select");#endif /* BD key on/off */ if(rkey&0x10) { if(v&0x10) { OPL->P_CH[6].op1_out[0] = OPL->P_CH[6].op1_out[1] = 0; OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT1]); OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT2]); } else { OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1]); OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2]); } } /* SD key on/off */ if(rkey&0x08) { if(v&0x08) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT2]); else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2]); }/* TAM key on/off */ if(rkey&0x04) { if(v&0x04) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT1]); else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -