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

📄 ymz280b.c

📁 十七种模拟器源代码 非常有用的作课程设计不可缺少的
💻 C
📖 第 1 页 / 共 2 页
字号:
/********************************************************************************************** * *   Yamaha YMZ280B driver *   by Aaron Giles * **********************************************************************************************/#include <stdio.h>#include <stdlib.h>#include <math.h>#include "driver.h"#include "sasound.h"#include "savegame.h"#include "loadroms.h"#define MAX_SAMPLE_CHUNK	10000#define FRAC_BITS			14#define FRAC_ONE			(1 << FRAC_BITS)#define FRAC_MASK			(FRAC_ONE - 1)/* struct describing a single playing ADPCM voice */struct YMZ280BVoice{	UINT8 playing;			/* 1 if we are actively playing */	UINT8 keyon;			/* 1 if the key is on */	UINT8 looping;			/* 1 if looping is enabled */	UINT8 mode;				/* current playback mode */	UINT16 fnum;			/* frequency */	UINT8 level;			/* output level */	UINT8 pan;				/* panning */	UINT32 start;			/* start address, in nibbles */	UINT32 stop;			/* stop address, in nibbles */	UINT32 loop_start;		/* loop start address, in nibbles */	UINT32 loop_end;		/* loop end address, in nibbles */	UINT32 position;		/* current position, in nibbles */	INT32 signal;			/* current ADPCM signal */	INT32 step;				/* current ADPCM step */	INT32 loop_signal;		/* signal at loop start */	INT32 loop_step;		/* step at loop start */	UINT32 loop_count;		/* number of loops so far */	INT32 output_left;		/* output volume (left) */	INT32 output_right;		/* output volume (right) */	INT32 output_step;		/* step value for frequency conversion */	INT32 output_pos;		/* current fractional position */	INT16 last_sample;		/* last sample output */	INT16 curr_sample;		/* current sample target */};struct YMZ280BChip{	int stream;						/* which stream are we using */	UINT8 *region_base;				/* pointer to the base of the region */	UINT8 current_register;			/* currently accessible register */	UINT8 status_register;			/* current status register */	UINT8 irq_state;				/* current IRQ state */	UINT8 irq_mask;					/* current IRQ mask */	UINT8 irq_enable;				/* current IRQ enable */	UINT8 keyon_enable;				/* key on enable */	double master_clock;			/* master clock frequency */	void (*irq_callback)(int);		/* IRQ callback */	struct YMZ280BVoice	voice[8];	/* the 8 voices */};static struct YMZ280BChip ymz280b[MAX_YMZ280B];static INT32 *accumulator;static INT16 *scratch;/* step size index shift table */static int index_scale[8] = { 0x0e6, 0x0e6, 0x0e6, 0x0e6, 0x133, 0x199, 0x200, 0x266 };/* lookup table for the precomputed difference */static int diff_lookup[16];INLINE void update_irq_state(struct YMZ280BChip *chip){	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);	}}INLINE void update_step(struct YMZ280BChip *chip, struct YMZ280BVoice *voice){	double frequency;	/* handle the sound-off case */	if (audio_sample_rate == 0)	{		voice->output_step = 0;		return;	}	/* compute the frequency */	if (voice->mode == 1)		frequency = chip->master_clock * (double)((voice->fnum & 0x0ff) + 1) * (1.0 / 256.0);	else		frequency = chip->master_clock * (double)((voice->fnum & 0x1ff) + 1) * (1.0 / 256.0);	voice->output_step = (UINT32)(frequency * (double)FRAC_ONE / (double)audio_sample_rate);}INLINE void update_volumes(struct YMZ280BVoice *voice){  if (voice->pan == 8)	{		voice->output_left = voice->level;		voice->output_right = voice->level;	}	else if (voice->pan < 8)	{		voice->output_left = voice->level;		voice->output_right = voice->level * voice->pan / 8;	}	else	{		voice->output_left = voice->level * (15 - voice->pan) / 8;		voice->output_right = voice->level;	}}/**********************************************************************************************     compute_tables -- compute the difference tables***********************************************************************************************/static void compute_tables(void){	int nib;	/* loop over all nibbles and compute the difference */	for (nib = 0; nib < 16; nib++)	{		int value = (nib & 0x07) * 2 + 1;		diff_lookup[nib] = (nib & 0x08) ? -value : value;	}}/**********************************************************************************************     generate_adpcm -- general ADPCM decoding routine***********************************************************************************************/static int generate_adpcm(struct YMZ280BVoice *voice, UINT8 *base, INT16 *buffer, int samples){	int position = voice->position;	int signal = voice->signal;	int step = voice->step;	int val;	/* two cases: first cases is non-looping */	if (!voice->looping)	{		/* loop while we still have samples to generate */		while (samples)		{			/* compute the new amplitude and update the current step */		  val = base[position / 2] >> ((~position & 1) << 2);			signal += (step * diff_lookup[val & 15]) / 8;			/* clamp to the maximum */			if (signal > 32767)				signal = 32767;			else if (signal < -32768)				signal = -32768;			/* adjust the step size and clamp */			step = (step * index_scale[val & 7]) >> 8;			if (step > 0x6000)				step = 0x6000;			else if (step < 0x7f)				step = 0x7f;			/* output to the buffer, scaling by the volume */			*buffer++ = signal;			samples--;			/* next! */			position++;			if ((UINT32)position >= voice->stop)				break;		}	}	/* second case: looping */	else	{		/* loop while we still have samples to generate */		while (samples)		{			/* compute the new amplitude and update the current step */		  val = base[position / 2] >> ((~position & 1) << 2);		  signal += (step * diff_lookup[val & 15]) / 8;			/* clamp to the maximum */			if (signal > 32767)				signal = 32767;			else if (signal < -32768)				signal = -32768;			/* adjust the step size and clamp */			step = (step * index_scale[val & 7]) >> 8;			if (step > 0x6000)				step = 0x6000;			else if (step < 0x7f)				step = 0x7f;			/* output to the buffer, scaling by the volume */			*buffer++ = signal;			samples--;			/* next! */			position++;			if ((UINT32)position == voice->loop_start && voice->loop_count == 0)			{				voice->loop_signal = signal;				voice->loop_step = step;			}			if ((UINT32)position >= voice->loop_end)			{				if (voice->keyon)				{					position = voice->loop_start;					signal = voice->loop_signal;					step = voice->loop_step;					voice->loop_count++;				}			}			if ((UINT32)position >= voice->stop)				break;		}	}	/* update the parameters */	voice->position = position;	voice->signal = signal;	voice->step = step;	return samples;}/**********************************************************************************************     generate_pcm8 -- general 8-bit PCM decoding routine***********************************************************************************************/static int generate_pcm8(struct YMZ280BVoice *voice, UINT8 *base, INT16 *buffer, int samples){	int position = voice->position;	int val;	/* two cases: first cases is non-looping */	if (!voice->looping)	{		/* loop while we still have samples to generate */		while (samples)		{			/* fetch the current value */			val = base[position / 2];			/* output to the buffer, scaling by the volume */			*buffer++ = (INT8)val * 256;			samples--;			/* next! */			position += 2;			if ((UINT32)position >= voice->stop)				break;		}	}	/* second case: looping */	else	{		/* loop while we still have samples to generate */		while (samples)		{			/* fetch the current value */			val = base[position / 2];			/* output to the buffer, scaling by the volume */			*buffer++ = (INT8)val * 256;			samples--;			/* next! */			position += 2;			if ((UINT32)position >= voice->loop_end)			{				if (voice->keyon)					position = voice->loop_start;			}			if ((UINT32)position >= voice->stop)				break;		}	}	/* update the parameters */	voice->position = position;	return samples;}/**********************************************************************************************     generate_pcm16 -- general 16-bit PCM decoding routine***********************************************************************************************/static int generate_pcm16(struct YMZ280BVoice *voice, UINT8 *base, INT16 *buffer, int samples){	int position = voice->position;	int val;	/* two cases: first cases is non-looping */	if (!voice->looping)	{		/* loop while we still have samples to generate */		while (samples)		{			/* fetch the current value */			val = (INT16)((base[position / 2 + 1] << 8) + base[position / 2]);			/* output to the buffer, scaling by the volume */			*buffer++ = val;			samples--;			/* next! */			position += 4;			if ((UINT32)position >= voice->stop)				break;		}	}	/* second case: looping */	else	{		/* loop while we still have samples to generate */		while (samples)		{			/* fetch the current value */			val = (INT16)((base[position / 2 + 1] << 8) + base[position / 2]);			/* output to the buffer, scaling by the volume */			*buffer++ = val;			samples--;			/* next! */			position += 4;			if ((UINT32)position >= voice->loop_end)			{				if (voice->keyon)					position = voice->loop_start;			}			if ((UINT32)position >= voice->stop)				break;		}	}	/* update the parameters */	voice->position = position;	return samples;}/**********************************************************************************************     ymz280b_update -- update the sound chip so that it is in sync with CPU execution***********************************************************************************************/static void ymz280b_update(int num, INT16 **buffer, int length){	struct YMZ280BChip *chip = &ymz280b[num];	INT32 *lacc = accumulator;	INT32 *racc = accumulator + length;	int v;	/* clear out the accumulator */	memset(accumulator, 0, 2 * length * sizeof(accumulator[0]));	/* loop over voices */	for (v = 0; v < 8; v++)	{		struct YMZ280BVoice *voice = &chip->voice[v];		INT16 prev = voice->last_sample;		INT16 curr = voice->curr_sample;		INT16 *curr_data = scratch;		INT32 *ldest = lacc;		INT32 *rdest = racc;

⌨️ 快捷键说明

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