⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ym2151.c

📁 这个是延伸mame的在wince平台下的游戏模拟器的代码
💻 C
📖 第 1 页 / 共 3 页
字号:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "driver.h"
#include "ym2151.h"

/*
**  some globals ...
*/

#define USE_MAME_TIMERS
/*undef this if you don't want MAME timer system to be used*/

typedef struct{      /*oscillator data */
	unsigned int phase;	/*accumulated oscillator phase (in indexes)    (fixed point)*/
	unsigned int freq;	/*oscillator frequency (in indexes per sample) (fixed point)*/
	signed int LFOpm;	/*phase modulation from LFO*/

	unsigned int volume;	/*oscillator volume (fixed point)   */
	signed int attack_volume;/*used for attack phase calculations*/

	unsigned int TL;	/*Total attenuation Level*/
	unsigned int delta_AR;	/*volume delta for attack  phase (fixed point)*/
	unsigned int delta_D1R;	/*volume delta for decay   phase (fixed point)*/
	unsigned int D1L;	/*when envelope reaches this level Envelope Generator goes into D2R*/
	unsigned int delta_D2R;	/*volume delta for sustain phase (fixed point)*/
	unsigned int delta_RR;	/*volume delta for release phase (fixed point)*/
	unsigned int state;	/*Envelope state: 4-attack(AR) 3-decay(D1R) 2-sustain(D2R) 1-release(RR) 0-off*/

	unsigned int AMSmask;   /*LFO AMS enable mask*/

	signed int * connect;	/*oscillator output direction*/

/*Begin of channel specific data*/
/*The trick : each operator number 0 contains channel specific data*/
	signed int OscilFB;	/*oscillator self feedback value used only by operators 0*/
	unsigned int FeedBack;	/*feedback shift value for operators 0 in each channel*/
	unsigned int KC; 	/*KC for each channel*/
	unsigned int KF;	/*KF for each channel*/
	unsigned int PMS;	/*PMS for each channel*/
	unsigned int AMS;	/*AMS for each channel*/
	unsigned int PAN;	/*bit 7-right enable, bit 6-left enable: 0-off, 1-on*/
/*End of channel specific data*/

	unsigned int key;	/*0=last key was KEYOFF, 1=last key was KEON*/

	unsigned int KS;	/*Key Scale*/
	unsigned int AR;	/*Attack rate*/
	unsigned int D1R;	/*Decay rate*/
	unsigned int D2R;	/*Sustain rate*/
	unsigned int RR;	/*Release rate*/
	unsigned int mul;	/*phase multiply*/
	unsigned int DT1;	/*DT1 index*32 */
	unsigned int DT2;	/*DT2 index*/
	unsigned int KCindex;	/*Used for LFO pm calculations ...........*/
	unsigned int DT1val;	/*used for LFO pm calculations ...........*/

} OscilRec;

/* here's the virtual YM2151 */
typedef struct ym2151_v{
	int status;		/*chip status (BUSY, IRQ Flags)*/

	OscilRec Oscils[32];	/*there are 32 operators in YM2151*/

	unsigned int LFOphase;	/*accumulated LFO phase (in indexes)    (fixed point)*/
	unsigned int LFOfrq;	/*LFO frequency (in indexes per sample) (fixed point)*/
	unsigned int PMD;	/*LFO Phase Modulation Depth*/
	unsigned int AMD;	/*LFO Amplitude Modulation Depth*/
	unsigned int LFOwave;	/*LFO waveform (0-saw, 1-square, 2-triangle, 3-random noise)*/
	unsigned int LFA;	/*current AM from LFO*/
	signed int LFP;		/*current PM from LFO*/

	unsigned int CT;	/*output control pins (bit7 CT2, bit6 CT1)*/
	unsigned int noise;	/*noise register (bit 7 - noise enable, bits 4-0 - noise freq*/

	unsigned int IRQenable;		/*IRQ enable for timer B (bit 3) and timer A (bit 2)*/
#ifdef USE_MAME_TIMERS
	void *TimATimer,*TimBTimer;	/* ASG 980324 -- added for tracking timers */
	double TimerATime[1024];	/*Timer A times for MAME*/
	double TimerBTime[256];		/*Timer B times for MAME*/
#else
	int TimA,TimB;			/*timer A,B enable (0-disabled)*/
	signed int TimAVal,TimBVal;	/*current value of timer*/
	unsigned int TimerA[1024];	/*Timer A deltas*/
	unsigned int TimerB[256];	/*Timer B deltas*/
#endif
	unsigned int TimAIndex,TimBIndex;/*timers' indexes*/

	void (*handler)(void);		/*IRQ function handler*/
	void (*porthandler)(int offset,int data);	/*port write handler*/

	unsigned int freq[11*12*64];	/*11 octaves, 12 semitones, 64 'cents' */
	/*
	*   Frequency-deltas to get the closest frequency possible.
	*   There're 11 octaves because of DT2 (max 950 cents over base frequency)
	*   and LFO phase modulation (max 700 cents _over_ AND _below_ base frequency)
	*   Summary:   octave  explanation
	*              0       note code - LFO PM
	*              1       note code
	*              2       note code
	*              3       note code
	*              4       note code
	*              5       note code
	*              6       note code
	*              7       note code
	*              8       note code
	*              9       note code + DT2 + LFO PM
	*              10      note code + DT2 + LFO PM
	*/

	signed int DT1freq[8*32];
	/*
	*   Frequency deltas for DT1. These deltas alter operator frequency
	*   after it has been taken from frequency-deltas table.
	*/

	unsigned int LFOfreq[256];  /*frequency deltas for LFO*/

	unsigned int A_Time[64+32]; /*attack deltas (64 keycodes + 32 RKS's = 96)*/
	unsigned int D_Time[64+32]; /*decay  deltas (64 keycodes + 32 RKS's = 96)*/

	unsigned int clock;	/* this will be passed from 2151intf.c */
	unsigned int sampfreq;	/* this will be passed from 2151intf.c */

	unsigned int need_refresh; /* 1 if emulator needs refreshing before calculating new samples*/
} YM2151;



/*
**  Shifts below are subject to change if sampling frequency changes...
*/
#define FREQ_SH 16  /* 16.16 fixed point for frequency calculations     */
#define LFO_SH 24   /*  8.24 fixed point for LFO frequency calculations */
#define ENV_SH 16   /* 16.16 fixed point for envelope calculations      */
#define TIMER_SH 16 /* 16.16 fixed point for timers calculations        */

/*if you change these values (ENV_SOMETHING) you have to take care of attack_curve*/
#define ENV_BITS 10
#define ENV_RES ((int)1<<ENV_BITS)
#define ENV_STEP (96.0/ENV_RES)

#define MAX_VOLUME_INDEX ((ENV_RES-1)<<ENV_SH)
#define MIN_VOLUME_INDEX ((1<<ENV_SH)-1)
#define VOLUME_OFF (ENV_RES<<ENV_SH)

#define SIN_BITS 12
#define SIN_LEN ((int)1<<SIN_BITS)
#define SIN_MASK (SIN_LEN-1)

#define LFO_BITS 8
#define LFO_LEN ((int)1<<LFO_BITS)
#define LFO_MASK (LFO_LEN-1)

#define FINAL_SH16 0  /*this shift is applied to final output of all channels to get 16-bit sample*/
#define FINAL_SH8 8   /*this shift is applied to final output of all channels to get 8-bit sample*/


#define TL_TAB_LEN (2*(ENV_RES + ENV_RES + ENV_RES + SIN_LEN))
static signed int * TL_TAB = NULL;
/*
 *  Offset in this table is calculated as:
 *
 *  1st ENV_RES:
 *     TL- main offset (Total attenuation Level), range 0 to 1023 (0-96 dB)
 *  2nd ENV_RES:
 *     current envelope value of the operator, range 0 to 1023 (0-96 dB)
 *  3rd ENV_RES:
 *     Amplitude Modulation from LFO, range 0 to 1023 (0-96dB)
 *  4th SIN_LEN:
 *     Sin Wave Offset from sin_tab, range 0 to about 56 dB only, but lets
 *     simplify things and assume sin could be 96 dB, range 0 to 1023
 *
 *  Length of this table is doubled because we have two separate parts
 *  for positive and negative halves of sin wave (above and below X axis).
*/

static signed int * sin_tab[SIN_LEN];
/* sin waveform table in decibel scale */

static unsigned int D1LTab[16];
/*decibel table to convert from D1L values to volume index*/

static unsigned int attack_curve[ENV_RES];
/*attack curve for envelope attack phase*/

static unsigned int KC_TO_INDEX[16*8];  /*8 octaves * 16 note codes*/
/*
 *   Translate from key code KC (OCT2 OCT1 OCT0 N3 N2 N1 N0) to
 *   index in frequency-deltas table.
*/


#define EG_ATT 4
#define EG_DEC 3
#define EG_SUS 2
#define EG_REL 1
#define EG_OFF 0


static unsigned char sample_16bit;	/* 1 -> 16 bit sample, 0 -> 8 bit */
static unsigned int YMNumChips;		/* total # of YM2151's emulated */


/*these variables stay here because of speedup purposes only */
static SAMP *bufL, *bufR;
static unsigned int mask[16];
static signed int c1,m2,c2; /*Phase Modulation input for operators 2,3,4*/
static signed int chanout;


static YM2151 * PSG;
static YM2151 * YMPSG = NULL;	/* array of YM2151's */

static unsigned char DT1Tab[4*32]={ /* 4*32 DT1 values */
/*
 *   DT1 defines offset in Hertz from base note * mul
 *
 *   This table is converted while initialization...
*/
/* DT1=0 */
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* DT1=1 */
  0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
  2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 9,10,
/* DT1=2 */
  1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5,
  5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,17,19,20,
/* DT1=3 */
  2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,
  8, 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22
};

static unsigned int DT2Tab[4]={ /* 4 DT2 values */
/*
 *   DT2 defines offset in cents from base note
 *
 *   This table defines offset in frequency-deltas table.
 *   User's Manual page 22
 *   Values below were calculated using formula:  value = orig.val / 1.5625
 *
 *	DT2=0 DT2=1 DT2=2 DT2=3
 *	0     600   781   950
*/
	0,    384,  500,  608
};

static unsigned int AttackTab[73]={
/*
 * This data is valid ONLY for YM2151. Other Yamaha's FM chips seems to use
 * different shape of envelope attack phase. I'm quite sure that curve of OPL2/3
 * is *similiar*, but much smoother. These chips seem to use something
 * like "a 42dB curve".
 *
 *    This data was reverse-engineered by me (Jarek Burczynski). Keep in mind
 * that I spent a _lot_ of time researching this information, so be so kind as
 * to send me an e-mail before you use it, please.
*/
	0  ,1  ,2  ,3  ,4  ,5  ,6  ,7  ,8  ,9  ,10 ,11 ,12 ,13 ,14 ,16,  /*16*/
	18 ,20 ,22 ,24 ,26 ,28 ,31 ,34 ,37 ,40 ,43 ,46 ,50 ,54 ,58 ,63,  /*16*/
	68 ,73 ,78 ,84 ,90 ,97 ,104,111,120,129,138,148,158,168,180,193, /*16*/
	207,222,238,254,271,289,308,329,352,377,404,433,464,498,535,575, /*16*/
	618,664,713,766,823,884,950,1021,1023  /*9*/
};

static unsigned char MULTab[16]={1,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30};

void init_tables(void)
{
	signed int x,i;
	double m;

	for(i=0; i<SIN_LEN; i++){
		m = sin(2*/*PI*/3.14159265358979323846*i/SIN_LEN);              /*count sin value*/
		if ( (m<0.0001) && (m>-0.0001) ){     /*is m near zero ?*/
			m = ENV_RES-1;
		}else{
			if (m>0.0){
				m = 20*log10(1.0/m);  /*and how many decibels is it?*/
				m = m / ENV_STEP;
			}else{
				m = 20*log10(-1.0/m); /*and how many decibels is it?*/
				m = (m / ENV_STEP) + TL_TAB_LEN/2;
			}
		}
		sin_tab[ i ] = &TL_TAB[ (unsigned int)m ];
	}

	for( x=0; x<TL_TAB_LEN/2; x++ ){
		if (x<ENV_RES)
			m = ((1<<(SIN_BITS+2))-1) / pow(10, x * ENV_STEP /20);
		else
			m = 0;
		TL_TAB[         x        ] = m;
		TL_TAB[ x + TL_TAB_LEN/2 ] = -m;
	}

	/* create (almost perfect) attack curve */
	for (i=0; i<ENV_RES; i++)                     /*clear the curve*/
		attack_curve[i] = MAX_VOLUME_INDEX;

	for (i=0; i<73; i++){                         /*create curve*/
		for (x=i*14; x<i*14+14; x++){
			attack_curve[x] = AttackTab[i] << ENV_SH;
		}
	}

	for (i=0; i<16; i++){
		m = (i<15?i:i+16) * (3.0/ENV_STEP);   /*every 3 dB except for all bits = '1' = 45dB+48dB*/
		x = m * (double)(1<<ENV_SH);
		D1LTab[i] = x;
	}

	/* calculate KC to index table */
	x=0;
	for (i=0; i<16*8; i++){
		KC_TO_INDEX[i]=((i>>4)*12*64) + x*64 + 12*64;
		if ((i&3)!=3) x++;	/* change note code */
		if ((i&15)==15) x=0;	/* new octave */
	}
}


void init_chip_tables(YM2151 *chip)
{
	int i,j,oct;
	double mult,pom,pom2,clk;

	double scaler;	/* formula below is true for chip clock=3579545 */
	/* so we need to scale its output accordingly to the chip clock */

	scaler= (double)chip->clock / 3579545.0;

	/*this loop calculates Hertz values for notes from c#0 to c-8*/
	/*including 64 'cents' (100/64 that is 1.5625 of real cent) for each semitone*/

	oct = 12*64;
	mult = (int)1<<FREQ_SH;
	for (i=0; i<11*12*64; i++){
		pom = scaler * 6.875 * pow (2, ((i+4*64)*1.5625/1200.0) ); /*13.75Hz is note A 12semitones below A-0, so C#0 is 4 semitones above then*/
		/*calculate phase increment for above precounted Hertz value*/
		j = ( (pom*SIN_LEN) / (double)chip->sampfreq )*mult; /*fixed point*/

		j /= 2.0; /*divided by 2, because our first octave is one octave below standard */
		chip->freq[i] = j;
	}

	mult = (int)1<<FREQ_SH;
	for (j=0; j<4; j++){
		for (i=0; i<32; i++){
			pom = ( (double)DT1Tab[j*32+i] * ((double)chip->clock/4.0) ) / (double)(1<<24);
			/*calculate phase increment for above precounted Hertz value*/
			chip->DT1freq[j*32+i] = ( (pom*SIN_LEN) / (double)chip->sampfreq )*mult; /*fixed point*/
			chip->DT1freq[(j+4)*32+i] = -chip->DT1freq[j*32+i];
		}
	}

	mult = (int)1<<LFO_SH;
	clk  = (double)chip->clock;
	for (i=0; i<256; i++){
		j = i & 0x0f;
		pom = fabs(  (clk/65536/(1<<(i/16)) ) - (clk/65536/32/(1<<(i/16)) * (j+1)) );
		/*calculate phase increment for above precounted Hertz value*/
		chip->LFOfreq[0xff-i] = ( (pom*LFO_LEN) / (double)chip->sampfreq ) * mult; /*fixed point*/
	}

	for (i=0; i<4; i++)
		chip->A_Time[i] = chip->D_Time[i] = 0;		/*infinity*/

	for (i=4; i<64; i++){
		pom2 = ( (double)chip->clock / (double)chip->sampfreq );
		if (i<60) pom2 *= 1.0 + (i&3)*0.25;
		pom2 *= 1<<((i>>2)-1);
		pom2 *= (double)(1<<ENV_SH);
		if (i<52){
			pom  = pom2 / 27876.0;   		/*AR scale value 0-12*/
		}else{
			if ( (i>=52) && (i<56) ){
				pom  = pom2 / 30600.0;   	/*AR scale value 13*/
			}else{
				if ( (i>=56) && (i<60) ){
					pom  = pom2 / 32200.0;	/*AR scale value 14*/
				}else{
					pom  = pom2 / 30400.0;	/*AR scale value 15*/
				}
			}
		}
		if (i==63) pom=(ENV_RES<<ENV_SH);
		pom2 = pom2 / 385303.0;				/*DR scale value*/
		chip->A_Time[i] = pom;
		chip->D_Time[i] = pom2;
	}

	for (i=0; i<32; i++){
		chip->A_Time[64+i]=chip->A_Time[63];
		chip->D_Time[64+i]=chip->D_Time[63];
	}

/* precalculate timers' deltas */
/* User's Manual pages 15,16  */
	mult = (int)1<<TIMER_SH;
	for (i=0; i<1024; i++){
		/* ASG 980324: changed to compute both TimerA and TimerATime */
		pom= ( 64.0  *  (1024.0-i) / chip->clock ) ;
		#ifdef USE_MAME_TIMERS
			chip->TimerATime[i] = pom;
		#else
			chip->TimerA[i] = pom * chip->sampfreq * mult;  /*number of samples that timer period takes (fixed point) */
		#endif
	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -