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

📄 es5506.c

📁 十七种模拟器源代码 非常有用的作课程设计不可缺少的
💻 C
📖 第 1 页 / 共 4 页
字号:
/********************************************************************************************** * *   Ensoniq ES5505/6 driver *   by Aaron Giles * **********************************************************************************************/#include <stdio.h>#include <stdlib.h>#include <math.h>#include "sasound.h"#include "driver.h"#include "adpcm.h"//#define DUMP 1/**********************************************************************************************     CONSTANTS***********************************************************************************************/#define BACKEND_INTERPOLATE		1#define LOG_COMMANDS			0#define MAX_SAMPLE_CHUNK		10000#define ULAW_MAXBITS			8#define FRAC_BITS				14#define FRAC_ONE				(1 << FRAC_BITS)#define FRAC_MASK				(FRAC_ONE - 1)#define CONTROL_BS1				0x8000#define CONTROL_BS0				0x4000#define CONTROL_CMPD			0x2000#define CONTROL_CA2				0x1000#define CONTROL_CA1				0x0800#define CONTROL_CA0				0x0400#define CONTROL_LP4				0x0200#define CONTROL_LP3				0x0100#define CONTROL_IRQ				0x0080#define CONTROL_DIR				0x0040#define CONTROL_IRQE			0x0020#define CONTROL_BLE				0x0010#define CONTROL_LPE				0x0008#define CONTROL_LEI				0x0004#define CONTROL_STOP1			0x0002#define CONTROL_STOP0			0x0001#define CONTROL_BSMASK			(CONTROL_BS1 | CONTROL_BS0)#define CONTROL_CAMASK			(CONTROL_CA2 | CONTROL_CA1 | CONTROL_CA0)#define CONTROL_LPMASK			(CONTROL_LP4 | CONTROL_LP3)#define CONTROL_LOOPMASK		(CONTROL_BLE | CONTROL_LPE)#define CONTROL_STOPMASK		(CONTROL_STOP1 | CONTROL_STOP0)/**********************************************************************************************     INTERNAL DATA STRUCTURES***********************************************************************************************//* struct describing a single playing voice */struct ES5506Voice{	/* external state */	UINT32		control;				/* control register */	UINT32		freqcount;				/* frequency count register */	UINT32		start;					/* start register */	UINT32		lvol;					/* left volume register */	UINT32		end;					/* end register */	UINT32		lvramp;					/* left volume ramp register */	UINT32		accum;					/* accumulator register */	UINT32		rvol;					/* right volume register */	UINT32		rvramp;					/* right volume ramp register */	UINT32		ecount;					/* envelope count register */	UINT32		k2;						/* k2 register */	UINT32		k2ramp;					/* k2 ramp register */	UINT32		k1;						/* k1 register */	UINT32		k1ramp;					/* k1 ramp register */	INT32		o4n1;					/* filter storage O4(n-1) */	INT32		o3n1;					/* filter storage O3(n-1) */	INT32		o3n2;					/* filter storage O3(n-2) */	INT32		o2n1;					/* filter storage O2(n-1) */	INT32		o2n2;					/* filter storage O2(n-2) */	INT32		o1n1;					/* filter storage O1(n-1) */	UINT32		exbank;					/* external address bank */	/* internal state */	UINT8		index;					/* index of this voice */	UINT8		filtcount;				/* filter count */};struct ES5506Chip{	int			stream;					/* which stream are we using */	UINT16 *	region_base[4];			/* pointer to the base of the region */	UINT32 		write_latch;			/* currently accumulated data for write */	UINT32 		read_latch;				/* currently accumulated data for read */	double 		master_clock;			/* master clock frequency */	void 		(*irq_callback)(int);	/* IRQ callback */	UINT16		(*port_read)(void);		/* input port read */	UINT8 		current_page;			/* current register page */	UINT8		active_voices;			/* number of active voices */	UINT8		mode;					/* MODE register */	UINT8		wst;					/* W_ST register */	UINT8		wend;					/* W_END register */	UINT8		lrend;					/* LR_END register */	UINT8		irqv;					/* IRQV register */	INT32		output_step;			/* step value for frequency conversion */	INT32		output_pos;				/* current fractional position */	INT32		last_lsample;			/* last sample output */	INT32		last_rsample;			/* last sample output */	INT32		curr_lsample;			/* current sample target */	INT32		curr_rsample;			/* current sample target */	struct 		ES5506Voice voice[32];	/* the 32 voices */};/**********************************************************************************************     GLOBALS***********************************************************************************************/static struct ES5506Chip es5506[MAX_ES5506];static INT32 *accumulator;static INT32 *scratch;static INT16 *ulaw_lookup;static UINT16 *volume_lookup;static FILE *eslog;/**********************************************************************************************     update_irq_state -- update the IRQ state***********************************************************************************************/INLINE static void update_irq_state(struct ES5506Chip *chip){#if 0	int irq_bits = chip->status_register & chip->irq_mask;	/* always off if the enable is off */	if (!chip->irq_enable)		irq_bits = 0;	/* update the state if changed */	if (irq_bits && !chip->irq_state)	{		chip->irq_state = 1;		if (chip->irq_callback)			(*chip->irq_callback)(1);	}	else if (!irq_bits && chip->irq_state)	{		chip->irq_state = 0;		if (chip->irq_callback)			(*chip->irq_callback)(0);	}#endif}/**********************************************************************************************     compute_tables -- compute static tables***********************************************************************************************/static int compute_tables(void){	int i;		/* allocate ulaw lookup table */	if (!ulaw_lookup)		ulaw_lookup = malloc(sizeof(ulaw_lookup[0]) << ULAW_MAXBITS);	if (!ulaw_lookup)		return 0;		/* generate ulaw lookup table */	for (i = 0; i < (1 << ULAW_MAXBITS); i++)	{		UINT16 rawval = (i << (16 - ULAW_MAXBITS)) | (1 << (15 - ULAW_MAXBITS));		UINT8 exponent = rawval >> 13;		UINT32 mantissa = (rawval << 3) & 0xffff;				if (exponent == 0)			ulaw_lookup[i] = (INT16)mantissa >> 7;		else		{			mantissa = (mantissa >> 1) | (~mantissa & 0x8000);			ulaw_lookup[i] = (INT16)mantissa >> (7 - exponent);		}	}	/* allocate volume lookup table */	if (!volume_lookup)		volume_lookup = malloc(sizeof(volume_lookup[0]) * 4096);	if (!volume_lookup)		return 0;		/* generate ulaw lookup table */	for (i = 0; i < 4096; i++)	{		UINT8 exponent = i >> 8;		UINT32 mantissa = (i & 0xff) | 0x100;				volume_lookup[i] = (mantissa << 11) >> (20 - exponent);	}	return 1;}/**********************************************************************************************     interpolate     backend_interpolate -- interpolate between two samples***********************************************************************************************/#define interpolate(sample1, sample2, accum)										\		(sample1 * (INT32)(0x800 - (voice->accum & 0x7ff)) + 						\		 sample2 * (INT32)(voice->accum & 0x7ff)) >> 11;#if BACKEND_INTERPOLATE#define backend_interpolate(sample1, sample2, position)								\		(sample1 * (INT32)(FRAC_ONE - position) + 									\		 sample2 * (INT32)position) >> FRAC_BITS;#else#define backend_interpolate(sample1, sample2, position)	sample1#endif/**********************************************************************************************     apply_filters -- apply the 4-pole digital filter to the sample***********************************************************************************************/#define apply_filters(voice, sample)															\do																								\{																								\	/* pole 1 is always low-pass using K1 */													\	sample = ((INT32)(voice->k1 >> 2) * (sample - voice->o1n1) / 16384) + voice->o1n1;			\	voice->o1n1 = sample;																		\																								\	/* pole 2 is always low-pass using K1 */													\	sample = ((INT32)(voice->k1 >> 2) * (sample - voice->o2n1) / 16384) + voice->o2n1;			\	voice->o2n2 = voice->o2n1;																	\	voice->o2n1 = sample;																		\																								\	/* remaining poles depend on the current filter setting */									\	switch (voice->control & CONTROL_LPMASK)													\	{																							\		case 0:																					\			/* pole 3 is high-pass using K2 */													\			sample = sample - voice->o2n2 + ((INT32)(voice->k2 >> 2) * voice->o3n1) / 32768 + voice->o3n1 / 2; \			voice->o3n2 = voice->o3n1;															\			voice->o3n1 = sample;																\																								\			/* pole 4 is high-pass using K2 */													\			sample = sample - voice->o3n2 + ((INT32)(voice->k2 >> 2) * voice->o4n1) / 32768 + voice->o4n1 / 2; \			voice->o4n1 = sample;																\			break;																				\																								\		case CONTROL_LP3:																		\			/* pole 3 is low-pass using K1 */													\			sample = ((INT32)(voice->k1 >> 2) * (sample - voice->o3n1) / 16384) + voice->o3n1;	\			voice->o3n2 = voice->o3n1;															\			voice->o3n1 = sample;																\																								\			/* pole 4 is high-pass using K2 */													\			sample = sample - voice->o3n2 + ((INT32)(voice->k2 >> 2) * voice->o4n1) / 32768 + voice->o4n1 / 2; \			voice->o4n1 = sample;																\			break;																				\																								\		case CONTROL_LP4:																		\			/* pole 3 is low-pass using K2 */													\			sample = ((INT32)(voice->k2 >> 2) * (sample - voice->o3n1) / 16384) + voice->o3n1;	\			voice->o3n2 = voice->o3n1;															\			voice->o3n1 = sample;																\																								\			/* pole 4 is low-pass using K2 */													\			sample = ((INT32)(voice->k2 >> 2) * (sample - voice->o4n1) / 16384) + voice->o4n1;	\			voice->o4n1 = sample;																\			break;																				\																								\		case CONTROL_LP4 | CONTROL_LP3:															\			/* pole 3 is low-pass using K1 */													\			sample = ((INT32)(voice->k1 >> 2) * (sample - voice->o3n1) / 16384) + voice->o3n1;	\			voice->o3n2 = voice->o3n1;															\			voice->o3n1 = sample;																\																								\			/* pole 4 is low-pass using K2 */													\			sample = ((INT32)(voice->k2 >> 2) * (sample - voice->o4n1) / 16384) + voice->o4n1;	\			voice->o4n1 = sample;																\			break;																				\	}																							\} while (0)/**********************************************************************************************     update_envelopes -- update the envelopes***********************************************************************************************/#define update_envelopes(voice, samples)											\do																					\{																					\	int count = (samples > 1 && samples > voice->ecount) ? voice->ecount : samples;	\																					\	/* decrement the envelope counter */											\	voice->ecount -= count;															\																					\	/* ramp left volume */															\	if (voice->lvramp)																\	{																				\		voice->lvol += (INT8)voice->lvramp * count;									\		if ((INT32)voice->lvol < 0) voice->lvol = 0;								\		else if (voice->lvol > 0xffff) voice->lvol = 0xffff;						\	}																				\																					\	/* ramp right volume */															\	if (voice->rvramp)																\	{																				\		voice->rvol += (INT8)voice->rvramp * count;									\		if ((INT32)voice->rvol < 0) voice->rvol = 0;								\		else if (voice->rvol > 0xffff) voice->rvol = 0xffff;						\	}																				\																					\	/* ramp k1 filter constant */													\	if (voice->k1ramp && ((INT32)voice->k1ramp >= 0 || !(voice->filtcount & 7)))	\	{																				\		voice->k1 += (INT8)voice->k1ramp * count;									\		if ((INT32)voice->k1 < 0) voice->k1 = 0;									\		else if (voice->k1 > 0xffff) voice->k1 = 0xffff;							\	}																				\																					\	/* ramp k2 filter constant */													\	if (voice->k2ramp && ((INT32)voice->k2ramp >= 0 || !(voice->filtcount & 7)))	\	{																				\		voice->k2 += (INT8)voice->k2ramp * count;									\		if ((INT32)voice->k2 < 0) voice->k2 = 0;									\		else if (voice->k2 > 0xffff) voice->k2 = 0xffff;							\	}																				\																					\	/* update the filter constant counter */										\	voice->filtcount += count;														\																					\} while (0)/**********************************************************************************************     check_for_end_forward     check_for_end_reverse -- check for loop end and loop appropriately***********************************************************************************************/#define check_for_end_forward(voice, accum)											\do																					\{																					\	/* are we past the end? */														\	if (accum > voice->end && !(voice->control & CONTROL_LEI))					\	{																				\		/* generate interrupt */													\		voice->control |= CONTROL_IRQ;												\																					\		/* handle the different types of looping */									\		switch (voice->control & CONTROL_LOOPMASK)									\		{																			\			/* non-looping */														\			case 0:																	\				voice->control |= CONTROL_STOP0;									\				goto alldone;														\																					\			/* uni-directional looping */											\			case CONTROL_LPE:														\				accum = voice->start + (accum - voice->end);						\				break;																\																					\			/* trans-wave looping */												\			case CONTROL_BLE:														\				accum = voice->start + (accum - voice->end);						\				voice->control = (voice->control & ~CONTROL_LOOPMASK) | CONTROL_LEI;\				break;																\																					\			/* bi-directional looping */											\			case CONTROL_LPE | CONTROL_BLE:											\				accum = voice->end - (accum - voice->end);							\				voice->control ^= CONTROL_DIR;										\				goto reverse;														\		}																			\	}																				\} while (0)#define check_for_end_reverse(voice, accum)											\do																					\{																					\	/* are we past the end? */														\	if (accum < voice->start && !(voice->control & CONTROL_LEI))					\	{																				\		/* generate interrupt */													\		voice->control |= CONTROL_IRQ;												\																					\		/* handle the different types of looping */									\		switch (voice->control & CONTROL_LOOPMASK)									\		{																			\			/* non-looping */														\			case 0:																	\				voice->control |= CONTROL_STOP0;									\				goto alldone;														\																					\			/* uni-directional looping */											\			case CONTROL_LPE:														\				accum = voice->end - (voice->start - accum);						\				break;																\																					\			/* trans-wave looping */												\			case CONTROL_BLE:														\				accum = voice->end - (voice->start - accum);						\				voice->control = (voice->control & ~CONTROL_LOOPMASK) | CONTROL_LEI;\				break;																\																					\			/* bi-directional looping */											\			case CONTROL_LPE | CONTROL_BLE:											\				accum = voice->start + (voice->start - accum);						\				voice->control ^= CONTROL_DIR;										\				goto reverse;														\		}																			\	}																				\} while (0)/**********************************************************************************************     generate_dummy -- generate nothing, just apply envelopes***********************************************************************************************/static void generate_dummy(struct ES5506Voice *voice, UINT16 *base, INT32 *lbuffer, INT32 *rbuffer, int samples){	UINT32 freqcount = voice->freqcount;	UINT32 accum = voice->accum;	/* outer loop, in case we switch directions */	while (samples > 0 && !(voice->control & CONTROL_STOPMASK))	{reverse:		/* two cases: first case is forward direction */		if (!(voice->control & CONTROL_DIR))		{			/* loop while we still have samples to generate */			while (samples--)			{				/* fetch two samples */				accum += freqcount;				/* update filters/volumes */				if (voice->ecount != 0)					update_envelopes(voice, 1);								/* check for loop end */				check_for_end_forward(voice, accum);			}		}		/* two cases: second case is backward direction */		else		{			/* loop while we still have samples to generate */			while (samples--)			{				/* fetch two samples */				accum -= freqcount;								/* update filters/volumes */				if (voice->ecount != 0)					update_envelopes(voice, 1);								/* check for loop end */				check_for_end_reverse(voice, accum);			}		}	}	/* if we stopped, process any additional envelope */

⌨️ 快捷键说明

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