📄 ym2151.c
字号:
/* initialize hardware registers */
for( i=0; i<32; i++){
memset(&chip->Oscils[i],'\0',sizeof(OscilRec));
chip->Oscils[i].volume = VOLUME_OFF;
}
for ( i=0; i<8; i++){
set_connect_feedback_pan(&chip->Oscils[i],0);
}
chip->LFOphase = 0;
chip->LFOfrq = 0;
chip->PMD = 0;
chip->AMD = 0;
chip->LFOwave = 0;
chip->LFA = 0;
chip->LFP = 0;
chip->IRQenable = 0;
#ifdef USE_MAME_TIMERS
/* ASG 980324 -- reset the timers before writing to the registers */
chip->TimATimer = 0;
chip->TimBTimer = 0;
#else
chip->TimA = 0;
chip->TimB = 0;
chip->TimAVal = 0;
chip->TimBVal = 0;
#endif
chip->TimAIndex = 0;
chip->TimBIndex = 0;
chip->CT = 0;
chip->noise = 0;
chip->status = 0;
chip->need_refresh = 1; /*emulator needs refresh after reset*/
}
void refresh_chip(void)
{
unsigned int kc_index_oscil, kc_index_channel, kc, chan;
unsigned char v;
OscilRec * osc;
if (PSG->need_refresh==0)
return;
PSG->need_refresh = 0;
for (chan=0; chan<8; chan++)
{
osc = &PSG->Oscils[chan];
kc = osc->KC;
kc_index_channel = KC_TO_INDEX[kc] + osc->KF;
kc >>=2;
/*calc freq begin operator 0*/
kc_index_oscil = kc_index_channel + osc->DT2; /*DT2 offset*/
osc->freq = PSG->freq[ kc_index_oscil ] * osc->mul;
osc->freq += PSG->DT1freq[ osc->DT1 + kc ]; /*DT1 value*/
/*calc freq end*/ /*calc envelopes begin*/
v = kc >> osc->KS;
osc->delta_AR = PSG->A_Time[ osc->AR + v]; /* 2*RR + RKS =max 95*/
osc->delta_D1R = PSG->D_Time[osc->D1R + v];
osc->delta_D2R = PSG->D_Time[osc->D2R + v];
osc->delta_RR = PSG->D_Time[ osc->RR + v];
/*calc envelopes end*/
osc+=8;
/*calc freq begin operator 1*/
kc_index_oscil = kc_index_channel + osc->DT2; /*DT2 offset*/
osc->freq = PSG->freq[ kc_index_oscil ] * osc->mul;
osc->freq += PSG->DT1freq[ osc->DT1 + kc ]; /*DT1 value*/
/*calc freq end*/ /*calc envelopes begin*/
v = kc >> osc->KS;
osc->delta_AR = PSG->A_Time[ osc->AR + v]; /* 2*RR + RKS =max 95*/
osc->delta_D1R = PSG->D_Time[osc->D1R + v];
osc->delta_D2R = PSG->D_Time[osc->D2R + v];
osc->delta_RR = PSG->D_Time[ osc->RR + v];
/*calc envelopes end*/
osc+=8;
/*calc freq begin operator 2*/
kc_index_oscil = kc_index_channel + osc->DT2; /*DT2 offset*/
osc->freq = PSG->freq[ kc_index_oscil ] * osc->mul;
osc->freq += PSG->DT1freq[ osc->DT1 + kc ]; /*DT1 value*/
/*calc freq end*/ /*calc envelopes begin*/
v = kc >> osc->KS;
osc->delta_AR = PSG->A_Time[ osc->AR + v]; /* 2*RR + RKS =max 95*/
osc->delta_D1R = PSG->D_Time[osc->D1R + v];
osc->delta_D2R = PSG->D_Time[osc->D2R + v];
osc->delta_RR = PSG->D_Time[ osc->RR + v];
/*calc envelopes end*/
osc+=8;
/*calc freq begin operator 3*/
kc_index_oscil = kc_index_channel + osc->DT2; /*DT2 offset*/
osc->freq = PSG->freq[ kc_index_oscil ] * osc->mul;
osc->freq += PSG->DT1freq[ osc->DT1 + kc ]; /*DT1 value*/
/*calc freq end*/ /*calc envelopes begin*/
v = kc >> osc->KS;
osc->delta_AR = PSG->A_Time[ osc->AR + v]; /* 2*RR + RKS =max 95*/
osc->delta_D1R = PSG->D_Time[osc->D1R + v];
osc->delta_D2R = PSG->D_Time[osc->D2R + v];
osc->delta_RR = PSG->D_Time[ osc->RR + v];
/*calc envelopes end*/
}
}
void lfo_calc(void)
{
signed int phase,pom;
phase = ( (PSG->LFOphase+=PSG->LFOfrq) >> LFO_SH ) & LFO_MASK;
switch(PSG->LFOwave){
case 0: /*saw ?*/
if (phase>=(LFO_LEN/2)){
PSG->LFP = 0;
}else{
PSG->LFP = 0;
}
phase = PSG->AMD - phase;
if (phase<0) PSG->LFA = 0;
else PSG->LFA = phase;
break;
case 1: /*square OK*/
if (phase>=(LFO_LEN/2)){
PSG->LFA = 0;
PSG->LFP = -PSG->PMD;
}else{
PSG->LFA = PSG->AMD;
PSG->LFP = PSG->PMD;
}
break;
case 2: /*triangle ?*/
pom = phase;
if (phase>=(LFO_LEN/2)){
phase = LFO_LEN - ((phase-(LFO_LEN/2))<<1);
phase = PSG->AMD - phase;
if (phase<0) PSG->LFA = 0;
else PSG->LFA = phase;
}else{
phase = PSG->AMD - (phase<<1);
if (phase<0) PSG->LFA = 0;
else PSG->LFA = phase;
}
if (pom<(LFO_LEN/4)){
phase = PSG->PMD - pom;
if (phase>0) phase = PSG->PMD - phase; else phase = PSG->PMD;
}else{
phase = PSG->PMD;
}
PSG->LFP = 0;
break;
case 3: /*noise (!!! real implementation is unknown !!!) */
pom = ( ( (phase & 1)^((phase&4)>>2) ) <<7) | (phase>>1);
phase = PSG->AMD - pom;
if (phase<0) PSG->LFA = 0;
else PSG->LFA = phase;
phase = PSG->PMD - pom;
if (abs(phase)>abs(PSG->PMD)) PSG->LFP = 0;
else PSG->LFP = phase;
break;
}
}
void pm_calc(OscilRec *op, int chan)
{
int inde,pom;
inde = PSG->LFP; /* -127..+127 (8bits signed)*/
switch( PSG->Oscils[chan].PMS ){
case 0: op->LFOpm=0; return; break;
case 1: inde<<=5; break;
case 2: inde<<=4; break;
case 3: inde<<=3; break;
case 4: inde<<=2; break;
case 5: inde<<=1; break;
case 6: inde>>=1; break;
case 7: inde = (inde/2)+inde+(inde*2); break;
}
pom = PSG->freq[ op->KCindex + inde ] * op->mul + op->DT1val;
}
static unsigned int volume_calc(OscilRec *op)
{
op->phase+=op->freq;
switch(op->state){
case EG_ATT: /*attack phase*/
if ( (op->attack_volume -= op->delta_AR) < MIN_VOLUME_INDEX ){
op->volume = MIN_VOLUME_INDEX;
op->state = EG_DEC;
}
else
op->volume = attack_curve[op->attack_volume>>ENV_SH];
break;
case EG_DEC: /*decay phase*/
if ( (op->volume += op->delta_D1R) > op->D1L )
op->state = EG_SUS;
break;
case EG_SUS: /*sustain phase*/
if ( (op->volume += op->delta_D2R) > MAX_VOLUME_INDEX ){
op->state = EG_OFF;
op->volume = VOLUME_OFF;
}
break;
case EG_REL: /*release phase*/
if ( (op->volume += op->delta_RR) > MAX_VOLUME_INDEX ){
op->state = EG_OFF;
op->volume = VOLUME_OFF;
}
break;
}
return op->TL + (op->volume>>ENV_SH);
}
#define op_calc(OP,env,pm) sin_tab[ ( (OP->phase>>FREQ_SH) + pm ) & SIN_MASK] [ env /*+ (AM & OP->AMSmask)*/ ]
static void chan_calc(unsigned int chan)
{
unsigned int env;
OscilRec *OP;
chanout = c1 = m2 = c2 = 0;
OP = &PSG->Oscils[chan]; /*M1*/
env = volume_calc(OP);
if (env < ENV_RES)
{
signed int out;
if (OP->FeedBack){
out = OP->OscilFB;
OP->OscilFB = op_calc(OP, env, (OP->OscilFB>>OP->FeedBack) );
out = (OP->OscilFB + out)/2;
}else{
out = op_calc(OP, env, 0);
}
if( !OP->connect ){
/* algorithm 5 */
c1 = m2 = c2 = out;
}else{
/* other algorithm */
*OP->connect += out;
}
}
OP+=16; /*C1*/
env = volume_calc(OP);
if( env < ENV_RES )
*OP->connect += op_calc(OP, env, c1);
OP-=8; /*M2*/
env = volume_calc(OP);
if( env < ENV_RES )
*OP->connect += op_calc(OP, env, m2);
OP+=16; /*C2*/
env = volume_calc(OP);
if( env < ENV_RES )
*OP->connect += op_calc(OP, env, c2);
}
/*
** Generate samples for one of the YM2151's
**
** 'num' is the number of virtual YM2151
** '**buffers' is table of pointers to the buffers: left and right
** 'length' is the number of samples should be generated
*/
void YM2151UpdateOne(int num, SAMP **buffers, int length)
{
unsigned int i;
signed int outl,outr;
bufL = buffers[0];
bufR = buffers[1];
PSG = &YMPSG[num];
refresh_chip();
#ifndef USE_MAME_TIMERS
/*calculate timers...*/
if (PSG->TimA){
PSG->TimAVal -= ( length << TIMER_SH );
if (PSG->TimAVal<=0){
PSG->TimA=0;
/* ASG 980324 - handled by real timers now*/
if ( PSG->IRQenable & 0x04 ){
PSG->status |= 1;
if (PSG->handler) (*PSG->handler)();
}
}
}
if (PSG->TimB){
PSG->TimBVal -= ( length << TIMER_SH );
if (PSG->TimBVal<=0){
PSG->TimB=0;
/* ASG 980324 - handled by real timers now*/
if ( PSG->IRQenable & 0x08 ){
PSG->status |= 2;
if (PSG->handler) (*PSG->handler)();
}
}
}
#endif
for (i=0; i<8; i++)
{
outl=PSG->Oscils[i].PAN;
mask[i*2] = (outl&0x40) ? 0xffffffff : 0x0;
mask[i*2+1]=(outl&0x80) ? 0xffffffff : 0x0;
}
for( i = 0; i<length; i++ ){
chan_calc(0);
outl = chanout & mask[0];
outr = chanout & mask[1];
chan_calc(1);
outl += (chanout & mask[2]);
outr += (chanout & mask[3]);
chan_calc(2);
outl += (chanout & mask[4]);
outr += (chanout & mask[5]);
chan_calc(3);
outl += (chanout & mask[6]);
outr += (chanout & mask[7]);
chan_calc(4);
outl += (chanout & mask[8]);
outr += (chanout & mask[9]);
chan_calc(5);
outl += (chanout & mask[10]);
outr += (chanout & mask[11]);
chan_calc(6);
outl += (chanout & mask[12]);
outr += (chanout & mask[13]);
chan_calc(7);
outl += (chanout & mask[14]);
outr += (chanout & mask[15]);
if (sample_16bit){ /*16 bit mode*/
outl >>= FINAL_SH16;
outr >>= FINAL_SH16;
if (outl > 32767) outl = 32767;
else if (outl < -32768) outl = -32768;
if (outr > 32767) outr = 32767;
else if (outr < -32768) outr = -32768;
((unsigned short*)bufL)[i] = (unsigned short)outl;
((unsigned short*)bufR)[i] = (unsigned short)outr;
}else{ /*8 bit mode*/
outl >>= FINAL_SH8;
outr >>= FINAL_SH8;
if (outl > 127) outl = 127;
else if (outl < -128) outl = -128;
if (outr > 127) outr = 127;
else if (outr < -128) outr = -128;
((unsigned char*)bufL)[i] = (unsigned char)outl;
((unsigned char*)bufR)[i] = (unsigned char)outr;
}
}
}
#if 0
#ifdef SAVE_SEPARATE_CHANNELS
for (j=7; j>=0; j--)
{
pom1= -(ChanOut[j] & mask[j]);
if (pom1 > 32767) pom1 = 32767;
else if (pom1 < -32768) pom1 = -32768;
fputc((unsigned short)pom1&0xff,sample[j]);
fputc(((unsigned short)pom1>>8)&0xff,sample[j]);
}
#endif
#endif
void YM2151SetIrqHandler(int n, void(*handler)(void))
{
YMPSG[n].handler = handler;
}
void YM2151SetPortWriteHandler(int n, void(*handler)(int offset, int data))
{
YMPSG[n].porthandler = handler;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -