📄 ym2151.c
字号:
for (i=0; i<256; i++){
/* ASG 980324: changed to compute both TimerB and TimerBTime */
pom= ( 1024.0 * (256.0-i) / chip->clock ) ;
#ifdef USE_MAME_TIMERS
chip->TimerBTime[i] = pom;
#else
chip->TimerB[i] = pom * chip->sampfreq * mult; /*number of samples that timer period takes (fixed point) */
#endif
}
}
INLINE void envelope_KONKOFF(OscilRec * op, int v)
{
/*OPL3 on SoundBlaster doesn't change envelope volume when KeyOn'ed */
/*However credit sound in Paper Boy and music tune in Toobin, both */
/*proove that YM2151 always zeroes volume after KEYON */
if (v&8)
{
if (!op->key){
op->key = 1; /*KEYON'ed*/
/*op->attack_volume = op->volume;*/ /*don't reset volume*/
op->attack_volume = op->volume = VOLUME_OFF; /*reset volume*/
op->OscilFB = op->phase = 0; /*clear feedback and phase */
op->state = EG_ATT; /*KEY ON = attack*/
}
}
else
{
if (op->key){
op->key = 0; /*KEYOFF'ed*/
op->state=EG_REL; /*release*/
}
}
op+=8;
if (v&0x20)
{
if (!op->key){
op->key = 1; /*KEYON'ed*/
/*op->attack_volume = op->volume;*/ /*don't reset volume*/
op->attack_volume = op->volume = VOLUME_OFF; /*reset volume*/
op->OscilFB = op->phase = 0; /*clear feedback and phase */
op->state = EG_ATT; /*KEY ON = attack*/
}
}
else
{
if (op->key){
op->key = 0; /*KEYOFF'ed*/
op->state=EG_REL; /*release*/
}
}
op+=8;
if (v&0x10)
{
if (!op->key){
op->key = 1; /*KEYON'ed*/
/*op->attack_volume = op->volume;*/ /*don't reset volume*/
op->attack_volume = op->volume = VOLUME_OFF; /*reset volume*/
op->OscilFB = op->phase = 0; /*clear feedback and phase */
op->state = EG_ATT; /*KEY ON = attack*/
}
}
else
{
if (op->key){
op->key = 0; /*KEYOFF'ed*/
op->state=EG_REL; /*release*/
}
}
op+=8;
if (v&0x40)
{
if (!op->key){
op->key = 1; /*KEYON'ed*/
/*op->attack_volume = op->volume;*/ /*don't reset volume*/
op->attack_volume = op->volume = VOLUME_OFF; /*reset volume*/
op->OscilFB = op->phase = 0; /*clear feedback and phase */
op->state = EG_ATT; /*KEY ON = attack*/
}
}
else
{
if (op->key){
op->key = 0; /*KEYOFF'ed*/
op->state=EG_REL; /*release*/
}
}
}
#ifdef USE_MAME_TIMERS
static void timer_callback_a (int n)
{
YM2151 *chip = &YMPSG[n];
chip->TimATimer=0;
if ( chip->IRQenable & 0x04 ){
chip->status |= 1;
if (chip->handler) (*chip->handler)();
}
}
static void timer_callback_b (int n)
{
YM2151 *chip = &YMPSG[n];
chip->TimBTimer=0;
if ( chip->IRQenable & 0x08 ){
chip->status |= 2;
if (chip->handler) (*chip->handler)();
}
}
#endif
static void set_connect_feedback_pan( OscilRec *om1, int v )
{
OscilRec *om2 = om1+8;
OscilRec *oc1 = om1+16;
OscilRec *oc2 = om1+24;
om1->PAN = v;
om1->FeedBack = (v>>3)&7 ? 8 - ((v>>3)&7) : 0;
/*for values 0,1,2,3,4,5,6,7 this formula gives: 0,7,6,5,4,3,2,1*/
/* set connect algorithm */
switch( v & 7 ){
case 0:
/* PG---M1---C1---M2---C2---OUT */
om1->connect = &c1;
oc1->connect = &m2;
om2->connect = &c2;
break;
case 1:
/* PG---M1-+-M2---C2---OUT */
/* PG---C1-+ */
om1->connect = &m2;
oc1->connect = &m2;
om2->connect = &c2;
break;
case 2:
/* PG---M1------+-C2---OUT */
/* PG---C1---M2-+ */
om1->connect = &c2;
oc1->connect = &m2;
om2->connect = &c2;
break;
case 3:
/* PG---M1---C1-+-C2---OUT */
/* PG---M2------+ */
om1->connect = &c1;
oc1->connect = &c2;
om2->connect = &c2;
break;
case 4:
/* PG---M1---C1-+--OUT */
/* PG---M2---C2-+ */
om1->connect = &c1;
oc1->connect = &chanout;
om2->connect = &c2;
break;
case 5:
/* +-C1-+ */
/* PG---M1-+-M2-+-OUT */
/* +-C2-+ */
om1->connect = 0; /* special mark */
oc1->connect = &chanout;
om2->connect = &chanout;
break;
case 6:
/* PG---M1---C1-+ */
/* PG--------M2-+-OUT */
/* PG--------C2-+ */
om1->connect = &c1;
oc1->connect = &chanout;
om2->connect = &chanout;
break;
case 7:
/* PG---M1-+ */
/* PG---C1-+-OUT */
/* PG---M2-+ */
/* PG---C2-+ */
om1->connect = &chanout;
oc1->connect = &chanout;
om2->connect = &chanout;
break;
}
oc2->connect = &chanout;
}
/* write a register on YM2151 chip number 'n' */
void YM2151WriteReg(int n, int r, int v)
{
YM2151 *chip = &(YMPSG[n]);
OscilRec * osc= &chip->Oscils[ r&0x1f ];
if ( (r>=0x80) || (r>=0x28 && r<0x38) || (r>=0x40 && r<0x60) )
chip->need_refresh = 1;
switch(r & 0xe0){
case 0x00:
switch(r){
case 0x01: /*LFO Reset(bit 1), Test Register (other bits)*/
if (v&2) chip->LFOphase=0;
break;
case 0x08:
envelope_KONKOFF(&chip->Oscils[ (v&7) ], v );
break;
case 0x0f: /*Noise mode select, noise freq*/
chip->noise = v;
break;
case 0x10: /*Timer A hi*/
chip->TimAIndex = (chip->TimAIndex & 0x03 ) | (v<<2);
break;
case 0x11: /*Timer A low*/
chip->TimAIndex = (chip->TimAIndex & 0x3fc) | (v & 3);
break;
case 0x12: /*Timer B */
chip->TimBIndex = v;
break;
case 0x14: /*CSM, irq flag reset, irq enable, timer start/stop*/
chip->IRQenable = v; /*bit 3-timer B, bit 2-timer A*/
if (v&0x20) chip->status &= 0xfd; /*FRESET B*/
if (v&0x10) chip->status &= 0xfe; /*FRESET A*/
if (v&0x02){ /*LOAD & START B*/
#ifdef USE_MAME_TIMERS
/* ASG 980324: added a real timer */
if (chip->TimBTimer) timer_remove(chip->TimBTimer);
chip->TimBTimer = timer_set (chip->TimerBTime[ chip->TimBIndex ], n, timer_callback_b);
#else
chip->TimB = 1;
chip->TimBVal = chip->TimerB[ chip->TimBIndex ];
#endif
}else{ /*STOP B*/
#ifdef USE_MAME_TIMERS
/* ASG 980324: added a real timer if we have a handler */
if (chip->TimBTimer) timer_remove (chip->TimBTimer);
chip->TimBTimer = 0;
#else
chip->TimB = 0;
#endif
}
if (v&0x01){ /*LOAD & START A*/
#ifdef USE_MAME_TIMERS
/* ASG 980324: added a real timer */
if (chip->TimATimer) timer_remove(chip->TimATimer);
chip->TimATimer = timer_set (chip->TimerATime[ chip->TimAIndex ], n, timer_callback_a);
#else
chip->TimA = 1;
chip->TimAVal = chip->TimerA[ chip->TimAIndex ];
#endif
}else{ /*STOP A*/
#ifdef USE_MAME_TIMERS
/* ASG 980324: added a real timer */
if (chip->TimATimer) timer_remove (chip->TimATimer);
chip->TimATimer = 0;
#else
chip->TimA = 0;
#endif
}
break;
case 0x18: /*LFO FREQ*/
chip->LFOfrq = chip->LFOfreq[ v ];
break;
case 0x19: /*PMD (bit 7=1) or AMD (bit 7=0) */
if (v&0x80)
chip->PMD = (v & 0x7f); /*7bits + sign bit*/
else
chip->AMD = ((v & 0x7f)<<1) | 1; /*7bits->8bits*/
break;
case 0x1b: /*CT2, CT1, LFO Waveform*/
chip->CT = v;
chip->LFOwave = v & 3;
if (chip->porthandler) (*chip->porthandler)(0 , (chip->CT)>>6 );
break;
default:
break;
}
break;
case 0x20:
switch(r & 0x18){
case 0x00: /*RL enable, Feedback, Connection */
set_connect_feedback_pan(&chip->Oscils[r&7], v );
break;
case 0x08: /*Key Code*/
chip->Oscils[ r&7 ].KC = v & 0x7f;
break;
case 0x10: /*Key Fraction*/
chip->Oscils[ r&7 ].KF = v >> 2 ;
break;
case 0x18: /*PMS,AMS*/
chip->Oscils[ r&7 ].PMS = (v>>4) & 7;
chip->Oscils[ r&7 ].AMS = v & 3;
break;
}
break;
case 0x40: /*DT1, MUL*/
osc->DT1 = (v<<1) & 0xe0;
osc->mul = MULTab [v & 0x0f];
break;
case 0x60: /*TL*/
osc->TL = (v&0x7f)<<(ENV_BITS-7); /*7bit TL*/
break;
case 0x80: /*KS, AR*/
osc->KS = 3-(v>>6);
osc->AR = (v&0x1f) << 1;
break;
case 0xa0: /*AMS-EN, D1R*/
osc->AMSmask = (v & 0x80) ? 0xffffffff : 0;
osc->D1R = (v&0x1f) << 1;
break;
case 0xc0: /*DT2, D2R*/
osc->DT2 = DT2Tab[(v>>6) & 3];
osc->D2R = (v&0x1f) << 1;
break;
case 0xe0: /*D1L, RR*/
osc->D1L = D1LTab[ (v>>4) & 0x0f ];
osc->RR = ((v&0x0f)<<2) | 2;
break;
}
}
int YM2151ReadStatus( int n )
{
return YMPSG[n].status;
}
/*
** Initialize YM2151 emulator(s).
**
** 'num' is the number of virtual YM2151's to allocate
** 'clock' is the chip clock in Hz
** 'rate' is sampling rate
** 'sample_bits' is 8/16 bit selector
*/
int YM2151Init(int num, int clock, int rate,int sample_bits )
{
int i;
if (YMPSG) return (-1); /* duplicate init. */
YMNumChips = num;
if (sample_bits==16)
sample_16bit=1;
else
sample_16bit=0;
YMPSG = (YM2151 *)malloc(sizeof(YM2151) * YMNumChips);
if (YMPSG == NULL) return (1);
TL_TAB = (signed int *)malloc(sizeof(signed int) * TL_TAB_LEN );
if (TL_TAB == NULL) { free(YMPSG); YMPSG=NULL; return (1); }
init_tables();
for ( i = 0 ; i < YMNumChips; i++ )
{
YMPSG[i].clock = clock;
YMPSG[i].sampfreq = rate ? rate : 10000; /* avoid division by 0 in init_chip_tables() */
YMPSG[i].handler = NULL; /*interrupt handler */
YMPSG[i].porthandler = NULL; /*port write handler*/
init_chip_tables(&YMPSG[i]);
YM2151ResetChip(i);
}
return(0);
}
void YM2151Shutdown()
{
if (!YMPSG) return;
free(YMPSG);
YMPSG = NULL;
if (TL_TAB){
free(TL_TAB);
TL_TAB=NULL;
}
}
/*
** reset all chip registers.
*/
void YM2151ResetChip(int num)
{
int i;
YM2151 *chip = &YMPSG[num];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -