📄 fm.c
字号:
}
ST->AR_TABLE[62] = EG_AED-1;
ST->AR_TABLE[63] = EG_AED-1;
for (i = 64;i < 94 ;i++){ /* make for overflow area */
ST->AR_TABLE[i] = ST->AR_TABLE[63];
ST->DR_TABLE[i] = ST->DR_TABLE[63];
}
}
/* ---------- reset one of channel ---------- */
static void reset_channel( FM_ST *ST , FM_CH *CH , int chan )
{
int c,s;
ST->mode = 0; /* normal mode */
ST->status = 0;
ST->TA = 0;
ST->TAC = 0;
ST->TB = 0;
ST->TBC = 0;
ST->timer_a_timer = 0;
ST->timer_b_timer = 0;
for( c = 0 ; c < chan ; c++ )
{
CH[c].fc = 0;
CH[c].PAN = OPN_CENTER; /* or OPM_CENTER */
for(s = 0 ; s < 4 ; s++ )
{
CH[c].SLOT[s].SEG = 0;
CH[c].SLOT[s].evm = ENV_MOD_OFF;
CH[c].SLOT[s].evc = EG_OFF;
CH[c].SLOT[s].eve = EG_OFF+1;
CH[c].SLOT[s].evs = 0;
}
}
}
/* ---------- generic table initialize ---------- */
static int FMInitTable( void )
{
int s,t;
double rate;
int i,j;
double pom;
/* allocate total level table */
TL_TABLE = malloc(TL_MAX*2*sizeof(int));
if( TL_TABLE == 0 ) 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 = 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];
}
/* envelope counter -> envelope output table */
for (i=0; i<EG_ENT; i++)
{
/* ATTACK curve */
/* !!!!! preliminary !!!!! */
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;
#ifdef SEG_SUPPORT
/* DECAY UPSIDE (SSG ENV) */
ENV_CURVE[(EG_UST>>ENV_BITS)+i]= EG_ENT-1-i;
#endif
}
/* off */
ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1;
/* decay to reattack envelope converttable */
j = EG_ENT-1;
for (i=0; i<EG_ENT; i++)
{
while( j && (ENV_CURVE[j] < i) ) j--;
DRAR_TABLE[i] = j<<ENV_BITS;
}
return 1;
}
static void FMCloseTable( void )
{
if( TL_TABLE ) free( TL_TABLE );
return;
}
/* OPN/OPM Mode Register Write */
INLINE void FMSetMode( FM_ST *ST ,int n,int v )
{
/* b7 = CSM MODE */
/* b6 = 3 slot mode */
/* b5 = reset b */
/* b4 = reset a */
/* b3 = timer enable b */
/* b2 = timer enable a */
/* b1 = load b */
/* b0 = load a */
ST->mode = v;
if( v & 0x20 )
{
ST->TBC = 0; /* timer stop */
ST->status &=0xfd; /* reset TIMER B */
if ( ST->irq && !(ST->status & ST->irqmask) )
{
ST->irq = 0;
/* callback user interrupt handler */
if(ST->IRQ_Handler) (ST->IRQ_Handler)(n,0);
}
/* External timer handler */
if (ST->Timer_Handler) (ST->Timer_Handler)(n,1,0,0);
}
if( v & 0x10 )
{
ST->status &=0xfe; /* reset TIMER A */
if ( ST->irq && !(ST->status & ST->irqmask) )
{
ST->irq = 0;
/* callback user interrupt handler */
if(ST->IRQ_Handler) (ST->IRQ_Handler)(n,0);
}
ST->TAC = 0; /* timer stop */
/* External timer handler */
if (ST->Timer_Handler) (ST->Timer_Handler)(n,0,0,0);
}
if( v & 0x02 )
{
if( ST->TBC == 0 )
{
ST->TBC = ( 256-ST->TB)<<4;
/* External timer handler */
if (ST->Timer_Handler) (ST->Timer_Handler)(n,1,(double)ST->TBC,ST->TimerBase);
}
}
if( v & 0x01 )
{
if( ST->TAC == 0 )
{
ST->TAC = (1024-ST->TA);
/* External timer handler */
if (ST->Timer_Handler) (ST->Timer_Handler)(n,0,(double)ST->TAC,ST->TimerBase);
}
}
}
/* Timer A Overflow */
INLINE void TimerAOver(int n,FM_ST *ST)
{
if(ST->mode & 0x04)
{
/* set status flag */
ST->status |= 0x01;
if ( !ST->irq && (ST->status & ST->irqmask) )
{
ST->irq = 1;
/* callback user interrupt handler */
if(ST->IRQ_Handler) (ST->IRQ_Handler)(n,1);
}
}
/* clear the counter */
ST->TAC = 0;
}
/* Timer B Overflow */
INLINE void TimerBOver(int n,FM_ST *ST)
{
if(ST->mode & 0x08)
{
/* set status flag */
ST->status |= 0x02;
if ( !ST->irq && (ST->status & ST->irqmask) )
{
ST->irq = 1;
/* callback user interrupt handler */
if(ST->IRQ_Handler) (ST->IRQ_Handler)(n,1);
}
}
/* update the counter */
ST->TBC = 0;
}
/* CSM Key Controll */
INLINE void CSMKeyControll(FM_CH *CH)
{
int ksl = KSL[CH->kcode];
/* all key off */
FM_KEYOFF(CH,SLOT1);
FM_KEYOFF(CH,SLOT2);
FM_KEYOFF(CH,SLOT3);
FM_KEYOFF(CH,SLOT4);
/* total level latch */
CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + ksl;
CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + ksl;
CH->SLOT[SLOT3].TLL = CH->SLOT[SLOT3].TL + ksl;
CH->SLOT[SLOT4].TLL = CH->SLOT[SLOT4].TL + ksl;
/* all key on */
FM_KEYON(CH,SLOT1);
FM_KEYON(CH,SLOT2);
FM_KEYON(CH,SLOT3);
FM_KEYON(CH,SLOT4);
}
#ifdef INTERNAL_TIMER
/* ---------- calcrate timer A ---------- */
INLINE void CALC_TIMER_A( int n, FM_ST *ST , FM_CH *CSM_CH ){
if( ST->TAC && (ST->Timer_Handler==0) )
if( (ST->TAC -= ST->freqbase) <= 0 ){
TimerAOver( n,ST );
/* CSM mode key,TL controll */
if( ST->mode & 0x80 ){ /* CSM mode total level latch and auto key on */
CSMKeyControll( CSM_CH );
}
}
}
/* ---------- calcrate timer B ---------- */
INLINE void CALC_TIMER_B( int n, FM_ST *ST,int step){
if( ST->TBC && (ST->Timer_Handler==0) )
if( (ST->TBC -= ST->freqbase*step) <= 0 ){
TimerBOver( n,ST );
}
}
#endif /* INTERNAL_TIMER */
#ifdef BUILD_OPN
/* ---------- priscaler set(and make time tables) ---------- */
void OPNSetPris(FM_OPN *OPN , int pris , int TimerPris, int SSGpris)
{
int fn;
/* frequency base */
OPN->ST.freqbase = (OPN->ST.rate) ? ((double)OPN->ST.clock * 4096.0 / OPN->ST.rate) / pris : 0;
/* Timer base time */
OPN->ST.TimerBase = (OPN->ST.rate) ? 1.0/((double)OPN->ST.clock / (double)TimerPris) : 0;
/* SSG part priscaler set */
if( SSGpris ) SSGClk( OPN->index, OPN->ST.clock * 2 / SSGpris );
/* make time tables */
init_timetables( &OPN->ST , OPN_DTTABLE , OPN_ARRATE , OPN_DRRATE );
/* make fnumber -> increment counter table */
for( fn=0 ; fn < 2048 ; fn++ )
{
/* it is freq table for octave 7 */
/* opn freq counter = 20bit */
OPN->FN_TABLE[fn] = (double)fn * OPN->ST.freqbase / 4096 * FREQ_RATE * (1<<7) / 2;
}
}
/* ---------- write a OPN mode register 0x20-0x2f ---------- */
static void OPNWriteMode(FM_OPN *OPN, int r, int v)
{
unsigned char c;
FM_CH *CH;
switch(r){
case 0x21: /* Test */
break;
case 0x22: /* LFO FREQ (YM2608/YM2612) */
/* 3.98Hz,5.56Hz,6.02Hz,6.37Hz,6.88Hz,9.63Hz,48.1Hz,72.2Hz */
/* FM2608[n].LFOIncr = FM2608[n].LFO_TABLE[v&0x0f]; */
break;
case 0x24: /* timer A High 8*/
OPN->ST.TA = (OPN->ST.TA & 0x03)|(((int)v)<<2);
break;
case 0x25: /* timer A Low 2*/
OPN->ST.TA = (OPN->ST.TA & 0x3fc)|(v&3);
break;
case 0x26: /* timer B */
OPN->ST.TB = v;
break;
case 0x27: /* mode , timer controll */
FMSetMode( &(OPN->ST),OPN->index,v );
break;
case 0x28: /* key on / off */
c = v&0x03;
if( c == 3 ) break;
if( (v&0x04) && (OPN->type & TYPE_6CH) ) c+=3;
CH = OPN->P_CH;
CH = &CH[c];
/* csm mode */
if( c == 2 && (OPN->ST.mode & 0x80) ) break;
if(v&0x10) FM_KEYON(CH,SLOT1); else FM_KEYOFF(CH,SLOT1);
if(v&0x20) FM_KEYON(CH,SLOT2); else FM_KEYOFF(CH,SLOT2);
if(v&0x40) FM_KEYON(CH,SLOT3); else FM_KEYOFF(CH,SLOT3);
if(v&0x80) FM_KEYON(CH,SLOT4); else FM_KEYOFF(CH,SLOT4);
break;
case 0x29: /* SCH,irq mask (YM2608) */
break;
}
}
/* ---------- write a OPN register (0x30-0xff) ---------- */
static void OPNWriteReg(FM_OPN *OPN, int r, int v)
{
unsigned char c;
FM_CH *CH;
FM_SLOT *SLOT;
/* 0x30 - 0xff */
if( (c = OPN_CHAN(r)) == 3 ) return; /* 0xX3,0xX7,0xXB,0xXF */
if( (r >= 0x100) && (OPN->type & TYPE_6CH) ) c+=3;
CH = OPN->P_CH;
CH = &CH[c];
SLOT = &(CH->SLOT[OPN_SLOT(r)]);
switch( r & 0xf0 ) {
case 0x30: /* DET , MUL */
set_det_mul(&OPN->ST,CH,SLOT,v);
break;
case 0x40: /* TL */
set_tl(CH,SLOT,v,(c == 2) && (OPN->ST.mode & 0x80) );
break;
case 0x50: /* KS, AR */
set_ar_ksr(CH,SLOT,v,OPN->ST.AR_TABLE);
break;
case 0x60: /* DR */
/* bit7 = AMS ENABLE(YM2612) */
set_dr(SLOT,v,OPN->ST.DR_TABLE);
break;
case 0x70: /* SR */
set_sr(SLOT,v,OPN->ST.DR_TABLE);
break;
case 0x80: /* SL, RR */
set_sl_rr(SLOT,v,OPN->ST.DR_TABLE);
break;
case 0x90: /* SSG-EG */
SLOT->SEG = v&0x0f;
break;
case 0xa0:
switch( OPN_SLOT(r) ){
case 0: /* 0xa0-0xa2 : FNUM1 */
{
unsigned int fn = (((unsigned int)( (CH->fn_h)&7))<<8) + v;
unsigned char blk = CH->fn_h>>3;
/* make keyscale code */
CH->kcode = (blk<<2)|OPN_FKTABLE[(fn>>7)];
/* make basic increment counter 32bit = 1 cycle */
CH->fc = OPN->FN_TABLE[fn]>>(7-blk);
CH->SLOT[SLOT1].Incr=-1;
}
break;
case 1: /* 0xa4-0xa6 : FNUM2,BLK */
CH->fn_h = v&0x3f;
break;
case 2: /* 0xa8-0xaa : 3CH FNUM1 */
if( r < 0x100)
{
unsigned int fn = (((unsigned int)(OPN->SL3.fn_h[c]&7))<<8) + v;
unsigned char blk = OPN->SL3.fn_h[c]>>3;
/* make keyscale code */
OPN->SL3.kcode[c]= (blk<<2)|OPN_FKTABLE[(fn>>7)];
/* make basic increment counter 32bit = 1 cycle */
OPN->SL3.fc[c] = OPN->FN_TABLE[fn]>>(7-blk);
(OPN->P_CH)[2].SLOT[SLOT1].Incr=-1;
}
break;
case 3: /* 0xac-0xae : 3CH FNUM2,BLK */
if( r < 0x100)
OPN->SL3.fn_h[c] = v&0x3f;
break;
}
break;
case 0xb0:
switch( OPN_SLOT(r) ){
case 0: /* 0xb0-0xb2 : FB,ALGO */
{
int feedback = (v>>3)&7;
CH->ALGO = v&7;
CH->FB = feedback ? 8 - feedback : 0;
set_algorythm( CH );
}
break;
case 1: /* 0xb4-0xb6 : L , R , AMS , PMS (YM2612/YM2608) */
if( OPN->type & TYPE_LFOPAN)
{
/* b0-2 PMS */
/* 0,3.4,6.7,10,14,20,40,80(cent) */
SLOT->pms = (v>>4) & 0x07;
/* b4-5 AMS */
/* 0,1.4,5.9,11.8(dB) */
SLOT->ams = v & 0x03;
/* PAN */
CH->PAN = (v>>6)&0x03; /* PAN : b6 = R , b7 = L */
set_algorythm( CH );
}
break;
}
break;
}
}
#endif /* BUILD_OPN */
#ifdef BUILD_YM2203
/*******************************************************************************/
/* YM2203 local section */
/*******************************************************************************/
static YM2203 *FM2203=NULL; /* array of YM2203's */
#ifdef FM_OUTPUT_PROC
void bufout16( unsigned short **buf, int data ){
*(*buf)++ = data >> OPN_OUTSB;
}
void bufout8( unsigned char **buf, int data ){
*(*buf)++ = data >> OPN_OUTSB_8;
}
#endif
/* ---------- update one of chip ----------- */
void YM2203UpdateOne(int num, FMSAMPLE *buffer, int length)
{
YM2203 *F2203 = &(FM2203[num]);
FM_OPN *OPN = &(FM2203[num].OPN);
int i,ch;
int data;
#ifndef FM_OUTPUT_PROC
FMSAMPLE *buf = buffer;
#else
unsigned char *buf = (unsigned char *)buffer;
#endif
State = &F2203->OPN.ST;
cch[0] = &F2203->CH[0];
cch[1] = &F2203->CH[1];
cch[2] = &F2203->CH[2];
/* frequency counter channel A */
CALC_FCOUNT( cch[0] );
/* frequency counter channel B */
CALC_FCOUNT( cch[1] );
/* frequency counter channel C */
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] );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -