📄 ym2151.c
字号:
pom = ( (PSG->freq[ kc_channel + op->DT2 ] + op->DT1v) * op->MUL ) >> 1; op->phase += (pom - op->freq); op+=8; pom = ( (PSG->freq[ kc_channel + op->DT2 ] + op->DT1v) * op->MUL ) >> 1; op->phase += (pom - op->freq); }}INLINE signed int op_calc(OscilRec * OP, unsigned int env, signed int pm){ unsigned int p; p = (env<<3) + sin_tab[ ( ((signed int)((OP->phase & ~FREQ_MASK) + (pm<<15))) >> FREQ_SH ) & SIN_MASK ]; if (p >= TL_TAB_LEN) return 0; return TL_TAB[p];}INLINE signed int op_calc1(OscilRec * OP, unsigned int env, signed int pm){ unsigned int p; signed int i; i = (OP->phase & ~FREQ_MASK) + pm;/*logerror("i=%08x (i>>16)&511=%8i phase=%i [pm=%08x] ",i, (i>>16)&511, OP->phase>>FREQ_SH, pm);*/ p = (env<<3) + sin_tab[ (i>>FREQ_SH) & SIN_MASK];/*logerror("(p&255=%i p>>8=%i) out= %i\n", p&255,p>>8, TL_TAB[p&255]>>(p>>8) );*/ if (p >= TL_TAB_LEN) return 0; return TL_TAB[p];}#define volume_calc(OP) (OP->TL + (((unsigned int)OP->volume)>>ENV_SH) + (AM & OP->AMSmask))INLINE void chan_calc(unsigned int chan){OscilRec *OP;unsigned int env;unsigned int AM; chanout[chan]= c1 = m2 = c2 = 0; AM = 0; OP = &PSG->Oscils[chan]; /*M1*/ if (OP->AMS) AM = PSG->LFA << (OP->AMS-1); if (OP->PMS) calc_lfo_pm(OP); env = volume_calc(OP); { signed int out; out = OP->FB0 + OP->FB; OP->FB0 = OP->FB; if (!OP->connect) /* algorithm 5 */ c1 = m2 = c2 = OP->FB0; else /* other algorithms */ *OP->connect = OP->FB0; OP->FB = 0; if (env < ENV_QUIET) OP->FB = op_calc1(OP, env, (out<<OP->FeedBack) ); } OP += 16; /*C1*/ env = volume_calc(OP); if (env < ENV_QUIET) *OP->connect += op_calc(OP, env, c1); OP -= 8; /*M2*/ env = volume_calc(OP); if (env < ENV_QUIET) *OP->connect += op_calc(OP, env, m2); OP += 16; /*C2*/ env = volume_calc(OP); if (env < ENV_QUIET) chanout[chan] += op_calc(OP, env, c2);}INLINE void chan7_calc(void){OscilRec *OP;unsigned int env;unsigned int AM; chanout[7]= c1 = m2 = c2 = 0; AM = 0; OP = &PSG->Oscils[7]; /*M1*/ if (OP->AMS) AM = PSG->LFA << (OP->AMS-1); if (OP->PMS) calc_lfo_pm(OP); env = volume_calc(OP); { signed int out; out = OP->FB0 + OP->FB; OP->FB0 = OP->FB; if (!OP->connect) /* algorithm 5 */ c1 = m2 = c2 = OP->FB0; else /* other algorithms */ *OP->connect = OP->FB0; OP->FB = 0; if (env < ENV_QUIET) OP->FB = op_calc1(OP, env, (out<<OP->FeedBack) ); } OP += 16; /*C1*/ env = volume_calc(OP); if (env < ENV_QUIET) *OP->connect += op_calc(OP, env, c1); OP -= 8; /*M2*/ env = volume_calc(OP); if (env < ENV_QUIET) *OP->connect += op_calc(OP, env, m2); OP += 16; /*C2*/ env = volume_calc(OP); if (PSG->noise & 0x80) { unsigned int noiseout; noiseout = 0; if (env < 0x3ff) noiseout = (env ^ 0x3ff) * 2; /*range of the YM2151 noise output is -2044 to 2040*/ chanout[7] += ((PSG->noiseRNG&0x10000) ? noiseout: -1 * (int)noiseout); /*bit 16 -> output*/ } else { if (env < ENV_QUIET) chanout[7] += op_calc(OP, env, c2); }}INLINE void advance(void){OscilRec *op;int i; if (!(PSG->test&2)) PSG->LFOphase += PSG->LFOfrq; /* The Noise Generator of the YM2151 is 17-bit shift register. ** Input to the bit16 is negated (bit0 XOR bit3) (EXNOR). ** Output of the register is negated (bit0 XOR bit3). ** Simply use bit16 as the noise output. */ PSG->noise_p += PSG->noise_f; i = (PSG->noise_p>>16); /*number of events (shifts of the shift register)*/ PSG->noise_p &= 0xffff; while (i) { unsigned int j; j = ( (PSG->noiseRNG ^ (PSG->noiseRNG>>3) ) & 1) ^ 1; PSG->noiseRNG = (j<<16) | (PSG->noiseRNG>>1); i--; } /* In real it seems that CSM keyon line is ORed with the KO line inside of the chip. ** This causes it to only work when KO is off, ie. 0 ** Below is my implementation only. */ if (PSG->CSMreq) /*CSM KEYON/KEYOFF seqeunce request*/ { if (PSG->CSMreq==2) /*KEYON*/ { op = &PSG->Oscils[0]; /*CH 0 M1*/ i = 32; do { if (op->key==0) /*_ONLY_ when KEY is OFF (checked)*/ { op->phase = 0; op->state = EG_ATT; } op++; i--; }while (i); PSG->CSMreq = 1; } else /*KEYOFF*/ { op = &PSG->Oscils[0]; /*CH 0 M1*/ i = 32; do { if (op->key==0) /*_ONLY_ when KEY is OFF (checked)*/ { if (op->state>EG_REL) op->state = EG_REL; } op++; i--; }while (i); PSG->CSMreq = 0; } } op = &PSG->Oscils[0]; /*CH0 M1*/ i = 32; do { op->phase += op->freq; switch(op->state) { case EG_ATT: /*attack phase*/ { signed int step; step = op->volume; op->volume -= op->delta_AR; step = (step>>ENV_SH) - (((unsigned int)op->volume)>>ENV_SH); /*number of levels passed since last time*/ if (step > 0) { signed int tmp_volume; tmp_volume = op->volume + (step<<ENV_SH); /*adjust by number of levels*/ do { tmp_volume = tmp_volume - (1<<ENV_SH) - ((tmp_volume>>4) & ~ENV_MASK); if (tmp_volume <= MIN_ATT_INDEX) break; step--; }while(step); op->volume = tmp_volume; } if (op->volume <= MIN_ATT_INDEX) { if (op->volume < 0) op->volume = 0; /*this is not quite correct (checked)*/ op->state = EG_DEC; } } break; case EG_DEC: /*decay phase*/ if ( (unsigned int)(op->volume += op->delta_D1R) >= op->D1L ) { op->volume = op->D1L; /*this is not quite correct (checked)*/ op->state = EG_SUS; } break; case EG_SUS: /*sustain phase*/ if ( (op->volume += op->delta_D2R) > MAX_ATT_INDEX ) { op->state = EG_OFF; op->volume = MAX_ATT_INDEX; } break; case EG_REL: /*release phase*/ if ( (op->volume += op->delta_RR) > MAX_ATT_INDEX ) { op->state = EG_OFF; op->volume = MAX_ATT_INDEX; } break; } op++; i--; }while (i);}#if 0INLINE signed int acc_calc(signed int value){ if (value>=0) { if (value < 0x0200) return (value); if (value < 0x0400) return (value & 0xfffffffe); if (value < 0x0800) return (value & 0xfffffffc); if (value < 0x1000) return (value & 0xfffffff8); if (value < 0x2000) return (value & 0xfffffff0); if (value < 0x4000) return (value & 0xffffffe0); return (value & 0xffffffc0); } /*else value < 0*/ if (value > -0x0200) return (value); if (value > -0x0400) return (value & 0xfffffffe); if (value > -0x0800) return (value & 0xfffffffc); if (value > -0x1000) return (value & 0xfffffff8); if (value > -0x2000) return (value & 0xfffffff0); if (value > -0x4000) return (value & 0xffffffe0); return (value & 0xffffffc0);}#endif/*first macro saves left and right channels to mono file*//*second macro saves left and right channels to stereo file*/#if 0 /*MONO*/ #ifdef SAVE_SEPARATE_CHANNELS #define SAVE_SINGLE_CHANNEL(j) \ { signed int pom= -(chanout[j] & PSG->PAN[j*2]); \ if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \ fputc((unsigned short)pom&0xff,sample[j]); \ fputc(((unsigned short)pom>>8)&0xff,sample[j]); } #else #define SAVE_SINGLE_CHANNEL(j) #endif#else /*STEREO*/ #ifdef SAVE_SEPARATE_CHANNELS #define SAVE_SINGLE_CHANNEL(j) \ { signed int pom = -(chanout[j] & PSG->PAN[j*2]); \ if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \ fputc((unsigned short)pom&0xff,sample[j]); \ fputc(((unsigned short)pom>>8)&0xff,sample[j]); \ pom = -(chanout[j] & PSG->PAN[j*2+1]); \ if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \ fputc((unsigned short)pom&0xff,sample[j]); \ fputc(((unsigned short)pom>>8)&0xff,sample[j]); \ } #else #define SAVE_SINGLE_CHANNEL(j) #endif#endif/*first macro saves left and right channels to mono file*//*second macro saves left and right channels to stereo file*/#if 1 /*MONO*/ #ifdef SAVE_SAMPLE #define SAVE_ALL_CHANNELS \ { signed int pom = outr; \ pom >>= FINAL_SH; \ if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \ /*pom = acc_calc(pom);*/ \ /*fprintf(sample[8]," %i\n",pom);*/ \ fputc((unsigned short)pom&0xff,sample[8]); \ fputc(((unsigned short)pom>>8)&0xff,sample[8]); \ } #else #define SAVE_ALL_CHANNELS #endif#else /*STEREO*/ #ifdef SAVE_SAMPLE #define SAVE_ALL_CHANNELS \ { signed int pom = outl; \ pom >>= FINAL_SH; \ if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \ fputc((unsigned short)pom&0xff,sample[8]); \ fputc(((unsigned short)pom>>8)&0xff,sample[8]); \ pom = outr; \ pom >>= FINAL_SH; \ if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \ fputc((unsigned short)pom&0xff,sample[8]); \ fputc(((unsigned short)pom>>8)&0xff,sample[8]); \ } #else #define SAVE_ALL_CHANNELS #endif#endif/*** 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 that should be generated*/void YM2151UpdateOne(int num, INT16 **buffers, int length){ int i; signed int outl,outr; SAMP *bufL, *bufR; bufL = buffers[0]; bufR = buffers[1]; PSG = &YMPSG[num]; #ifdef USE_MAME_TIMERS /* ASG 980324 - handled by real timers now */ #else if (PSG->TimB) { PSG->TimBVal -= ( length << TIMER_SH ); if (PSG->TimBVal<=0) { PSG->TimBVal += PSG->TimerB[ PSG->TimBIndex ]; if ( PSG->IRQenable & 0x08 ) { int oldstate = PSG->status & 3; PSG->status |= 2; if ((!oldstate) && (PSG->irqhandler)) (*PSG->irqhandler)(1); } } } #endif for (i=0; i<length; i++) { chan_calc(0); SAVE_SINGLE_CHANNEL(0) chan_calc(1); SAVE_SINGLE_CHANNEL(1) chan_calc(2); SAVE_SINGLE_CHANNEL(2) chan_calc(3); SAVE_SINGLE_CHANNEL(3) chan_calc(4); SAVE_SINGLE_CHANNEL(4) chan_calc(5); SAVE_SINGLE_CHANNEL(5) chan_calc(6); SAVE_SINGLE_CHANNEL(6) chan7_calc(); SAVE_SINGLE_CHANNEL(7) SAVE_ALL_CHANNELS outl = chanout[0] & PSG->PAN[0]; outr = chanout[0] & PSG->PAN[1]; outl += (chanout[1] & PSG->PAN[2]); outr += (chanout[1] & PSG->PAN[3]); outl += (chanout[2] & PSG->PAN[4]); outr += (chanout[2] & PSG->PAN[5]); outl += (chanout[3] & PSG->PAN[6]); outr += (chanout[3] & PSG->PAN[7]); outl += (chanout[4] & PSG->PAN[8]); outr += (chanout[4] & PSG->PAN[9]); outl += (chanout[5] & PSG->PAN[10]); outr += (chanout[5] & PSG->PAN[11]); outl += (chanout[6] & PSG->PAN[12]); outr += (chanout[6] & PSG->PAN[13]); outl += (chanout[7] & PSG->PAN[14]); outr += (chanout[7] & PSG->PAN[15]); outl >>= FINAL_SH; outr >>= FINAL_SH; if (outl > MAXOUT) outl = MAXOUT; else if (outl < MINOUT) outl = MINOUT; if (outr > MAXOUT) outr = MAXOUT; else if (outr < MINOUT) outr = MINOUT; ((SAMP*)bufL)[i] = (SAMP)outl; ((SAMP*)bufR)[i] = (SAMP)outr; #ifdef USE_MAME_TIMERS /* ASG 980324 - handled by real timers now */ #else /* calculate timer A */ if (PSG->TimA) { PSG->TimAVal -= ( 1 << TIMER_SH ); if (PSG->TimAVal <= 0) { PSG->TimAVal += PSG->TimerA[ PSG->TimAIndex ]; if (PSG->IRQenable & 0x04) { int oldstate = PSG->status & 3; PSG->status |= 1; if ((!oldstate) && (PSG->irqhandler)) (*PSG->irqhandler)(1); } if (PSG->IRQenable & 0x80) PSG->CSMreq = 2; /*request KEYON/KEYOFF sequence*/ } } #endif lfo_calc(); advance(); }}void YM2151SetIrqHandler(int n, void(*handler)(int irq)){ YMPSG[n].irqhandler = handler;}void YM2151SetPortWriteHandler(int n, mem_write_handler handler){ YMPSG[n].porthandler = handler;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -