📄 fm.c
字号:
for( ch=0;ch<6;ch++) FM_CALC_CH( cch[ch] );
/* get left & right output */
dataL = Limit( outd[OPN_CENTER] + outd[OPN_LEFT], OPN_MAXOUT, OPN_MINOUT );
dataR = Limit( outd[OPN_CENTER] + outd[OPN_RIGHT], OPN_MAXOUT, OPN_MINOUT );
/* buffering */
if( sample_16bit )
{
#ifdef FM_STEREO_MIX /* stereo mixing */
/* stereo mix */
((unsigned long *)bufL)[i] = ((dataL>>OPN_OUTSB)<<16)|(dataR>>OPN_OUTSB);
#else
/* stereo separate */
((unsigned short *)bufL)[i] = dataL>>OPN_OUTSB;
((unsigned short *)bufR)[i] = dataR>>OPN_OUTSB;
#endif
}
else
{
#ifdef FM_STEREO_MIX /* stereo mixing */
/* stereo mix */
((unsigned shart *)bufL)[i] = ((dataL>>OPN_OUTSB_8)<<8)|(dataR>>OPN_OUTSB_8);
#else
/* stereo separate */
((unsigned char *)bufL)[i] = dataL>>OPN_OUTSB_8;
((unsigned char *)bufR)[i] = dataR>>OPN_OUTSB_8;
#endif
}
#ifdef LFO_SUPPORT
CALC_LOPM_LFO;
#endif
#ifdef INTERNAL_TIMER
/* timer controll */
CALC_TIMER_A( num, State , cch[2] );
#endif
}
#ifdef INTERNAL_TIMER
CALC_TIMER_B( num, State , length );
#endif
}
/* -------------------------- YM2608(OPNA) ---------------------------------- */
int YM2608Init(int num, int clock, int rate, int bitsize,
FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler)
{
int i,j;
if (FM2608) return (-1); /* duplicate init. */
FMNumChips = num;
if( bitsize == 16 ) sample_16bit = 1;
else sample_16bit = 0;
/* allocate extend state space */
if( (FM2608 = (YM2608 *)malloc(sizeof(YM2608) * FMNumChips))==NULL)
return (-1);
/* clear */
memset(FM2608,0,sizeof(YM2608) * FMNumChips);
/* allocate total level table (128kb space) */
if( !FMInitTable() )
{
free( FM2608 );
return (-1);
}
for ( i = 0 ; i < FMNumChips; i++ ) {
FM2608[i].OPN.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;
/* Extend handler */
FM2608[i].OPN.ST.Timer_Handler = TimerHandler;
FM2608[i].OPN.ST.IRQ_Handler = IRQHandler;
YM2608ResetChip(i);
}
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);
/* Reset Priscaler */
OPNSetPris( OPN, 6*24, 6*24,4*2); /* OPN 1/6 , SSG 1/4 */
/* reset SSG section */
SSGReset(OPN->index);
/* status clear */
OPN->ST.irqmask = 0x03;
OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */
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 */
/* reset RITHM unit */
}
/* YM2608 write */
/* n = number */
/* a = address */
/* v = value */
int YM2608Write(int n, int a,int 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 */
break;
case 0x2e: /* divider sel */
OPNSetPris( OPN, 3*24, 3*24,2*2); /* OPN 1/3 , SSG 1/2 */
break;
case 0x2f: /* divider sel */
OPNSetPris( OPN, 2*24, 2*24,1*2); /* OPN 1/2 , SSG 1/1 */
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: /* Rhythm section */
YM2608UpdateReq(n);
YM2608RhythmWrite(n,F2608->address1,v);
break;
case 0x20: /* Mode Register */
YM2608UpdateReq(n);
OPNWriteMode(OPN,addr,v);
default: /* OPN section */
YM2608UpdateReq(n);
/* write register */
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 */
YM2608ADPCMWrite(n,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;
}
unsigned char 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 */
ret = F2608->OPN.ST.status & 0x83;
break;
case 1: /* status 0 */
if( addr < 16 ) ret = SSGRead(n);
break;
case 2: /* status 1 : + ADPCM status */
ret = F2608->OPN.ST.status;
break;
case 3:
ret = 0;
break;
}
return ret;
}
int YM2608TimerOver(int n,int c)
{
YM2608 *F2608 = &(FM2608[n]);
if( c )
{ /* Timer B */
TimerBOver( n,&(F2608->OPN.ST) );
}
else
{ /* Timer A */
YM2608UpdateReq(n);
/* timer update */
TimerAOver( n,&(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;
}
#if 0
/* ---------- return the buffer ---------- */
FMSAMPLE **YM2608Buffer(int n)
{
return &(FM2608[n].Buf);
}
#endif
#if 0
/* ---------- set buffer ---------- */
int YM2608SetBuffer(int n, FMSAMPLE **buf )
{
int i;
for( i = 0 ; i < YM2608_NUMBUF ; i++){
FM2608[n].Buf[i] = buf[i];
if( cur_chip == &FM2608[n] ) cur_chip = NULL;
}
return 0;
}
#endif
#endif /* BUILD_YM2608 */
#ifdef BUILD_YM2610
#define ADPCM_DECODE_RANGE 32768
#define ADPCM_DECODE_MIN (-ADPCM_DECODE_RANGE+1)
#define ADPCM_DECODE_MAX (ADPCM_DECODE_RANGE-1)
/* -------------------------- YM2610(OPNB) ---------------------------------- */
/***************************************************************/
/* ADPCM units are made by Hiromitsu Shioya (MMSND) */
/***************************************************************/
static YM2610 *FM2610=NULL; /* array of YM2610's */
static char *pcmbufA, *pcmbufB;
static unsigned int pcmsizeA, pcmsizeB;
/************************************************************/
/************************************************************/
/* --------------------- subroutines --------------------- */
/************************************************************/
/************************************************************/
static int decode_table1[16] = {
1, 3, 5, 7, 9, 11, 13, 15,
-1, -3, -5, -7, -9, -11, -13, -15,
};
static int decode_table2[16] = {
57, 57, 57, 57, 77, 102, 128, 153,
57, 57, 57, 57, 77, 102, 128, 153,
};
/**** ADPCM A(YAMAHA type) *****/
INLINE void OPNB_ADPCM_CALC_CHA( ADPCM_CH *ch )
{
unsigned int bit, addr, mask, stepaddr, endaddr;
int data;
addr = ch->now_addr;
ch->now_addr += ch->step;
mask = ~( ( 1 << ADPCM_SHIFT ) -1 );
if ( ( addr & mask ) < ( ch->now_addr & mask ) ) {
endaddr = ch->now_addr & mask;
bit = (((addr & mask)>>(ADPCM_SHIFT-2))&4)^4;
for ( stepaddr = addr & mask; stepaddr < endaddr; stepaddr += ( 1 << ADPCM_SHIFT ) ) {
addr = ( ( stepaddr >> ( ADPCM_SHIFT + 1 ) ) & 0x003fffff ) + ch->start;
if ( addr > ch->end ) {
ch->flag = 0;
return;
}
if ( addr > pcmsizeA ) {
return;
}
data = ( *( pcmbufA + addr ) >> bit ) & 0x0f;
bit ^= 4;
ch->adpcmx = Limit( ch->adpcmx + ( ( decode_table1[data] * ch->adpcmd ) / ADPCMA_CURVE_DIVIDE ), ADPCM_DECODE_MAX, ADPCM_DECODE_MIN );
ch->adpcmd = Limit( ( ch->adpcmd * decode_table2[data] ) / 64, 24576, 127 );
}
}
/* output for work of output channels (outd[OPNxxxx])*/
*(ch->pan) += ch->adpcmx * ch->volume;
}
/****************************************************************/
/****************************************************************/
static int jedi_table[16][49];
static int decodeb_table1[16] = {
-1, -1, -1, -1, 2, 5, 7, 9,
-1, -1, -1, -1, 2, 5, 7, 9
};
static int decodeb_table2[49] = {
0x0010, 0x0011, 0x0013, 0x0015, 0x0017, 0x0019, 0x001c, 0x001f,
0x0022, 0x0025, 0x0029, 0x002d, 0x0032, 0x0037, 0x003c, 0x0042,
0x0049, 0x0050, 0x0058, 0x0061, 0x006b, 0x0076, 0x0082, 0x008f,
0x009d, 0x00ad, 0x00be, 0x00d1, 0x00e6, 0x00fd, 0x0117, 0x0133,
0x0151, 0x0173, 0x0198, 0x01c1, 0x01ee, 0x0220, 0x0256, 0x0292,
0x02d4, 0x031c, 0x036c, 0x03c3, 0x0424, 0x048e, 0x0502, 0x0583,
0x0610
};
static void InitOPNB_ADPCMBTable(void){
int ta,tb,tc;
for(ta=0;ta<49;ta++){
for(tb=0;tb<16;tb++){
tc=0;
if(tb&0x04){tc+=(decodeb_table2[ta]);}
if(tb&0x02){tc+=(decodeb_table2[ta]>>1);}
if(tb&0x01){tc+=(decodeb_table2[ta]>>2);}
tc+=(decodeb_table2[ta]>>3);
if(tb&0x08){tc=(0-tc);}
jedi_table[tb][ta]=tc;
}
}
}
/**** ADPCM B(OKI? type)*****/
INLINE void OPNB_ADPCM_CALC_CHB( ADPCM_CH *ch )
{
unsigned int bit, addr, mask, stepaddr, endaddr;
int data;
addr = ch->now_addr;
ch->now_addr += ch->step;
mask = ~( ( 1 << ADPCM_SHIFT ) -1 );
if ( ( addr & mask ) < ( ch->now_addr & mask ) ) {
endaddr = ch->now_addr & mask;
bit = (((addr & mask)>>(ADPCM_SHIFT-2))&4)^4;
for( stepaddr = addr & mask; stepaddr < endaddr; stepaddr += ( 1 << ADPCM_SHIFT ) ) {
addr = ( ( stepaddr >> ( ADPCM_SHIFT + 1 ) ) & 0x003fffff ) + ch->start;
if ( addr > ch->end ) {
ch->flag = 0;
return;
}
if ( addr > pcmsizeB ) {
return;
}
data = ( *( pcmbufB + addr ) >> bit ) & 0x0f;
bit ^= 4;
ch->adpcmx = Limit( ch->adpcmx + (jedi_table[data][ch->adpcmd] / ADPCMB_CURVE_DIVIDE), (ADPCM_DECODE_MAX>>0), (ADPCM_DECODE_MIN>>0) );
ch->adpcmd = Limit( ch->adpcmd + decodeb_table1[data], 48, 0 );
}
}
/* output for work of output channels (outd[OPNxxxx])*/
*(ch->pan) += ch->adpcmx * ch->volume;
}
/* ---------- update one of chip ----------- */
void YM2610UpdateOne(int num, FMSAMPLE **buffer, int length)
{
YM2610 *F2610 = &(FM2610[num]);
FM_OPN *OPN = &(FM2610[num].OPN);
#ifndef FM_OUTPUT_PROC
static FMSAMPLE *buf[YM2610_NUMBUF];
#else
static unsigned char *buf[YM2610_NUMBUF];
#endif
int dataR,dataL;
int i,j;
/* buffer setup */
#ifndef FM_OUTPUT_PROC
for( i = 0; i < YM2610_NUMBUF; i++ ) buf[i] = buffer[i];
#else
for( i = 0; i < YM2610_NUMBUF; i++ ) buf[i] = (unsigned char *)buffer[i];
#endif
if( (void *)F2610 != cur_chip ){
cur_chip = (void *)F2610;
State = &OPN->ST;
cch[0] = &F2610->CH[0];
cch[1] = &F2610->CH[1];
cch[2] = &F2610->CH[2];
cch[3] = &F2610->CH[3];
cch[4] = &F2610->CH[4];
cch[5] = &F2610->CH[5];
/* setup adpcm rom address */
pcmbufA = F2610->pcmbuf[0];
pcmsizeA = F2610->pcm_size[0];
pcmbufB = F2610->pcmbuf[1];
pcmsizeB = F2610->pcm_size[1];
}
/* update frequency counter */
/* CALC_FCOUNT( cch[0] ); */
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 CALC_FCOUNT( cch[2] );
/* CALC_FCOUNT( cch[3] ); */
CALC_FCOUNT( cch[4] );
CALC_FCOUNT( cch[5] );
/* buffering */
for( i=0; i < length ; i++ )
{
/* clear output acc. */
outd[OPN_LEFT] = outd[OPN_RIGHT]= outd[OPN_CENTER] = 0;
/**** deltaT ADPCM ****/
if( F2610->adpcm[6].flag )
{
OPNB_ADPCM_CALC_CHA( &F2610->adpcm[6]);
if( F2610->adpcm[6].flag == 0)
F2610->adpcm_justfinished |= F2610->adpcm[6].flagMask & F2610->adpcm_statusmask;
}
/* FM */
FM_CALC_CH( cch[1] );
FM_CALC_CH( cch[2] );
FM_CALC_CH( cch[4] );
FM_CALC_CH( cch[5] );
for( j = 0; j < 6; j++ )
{
/**** ADPCM ****/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -