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

📄 adpcm.c

📁 这个是延伸mame的在wince平台下的游戏模拟器的代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 *   streaming ADPCM driver
 *   by Aaron Giles
 *
 *   Library to transcode from an ADPCM source to raw PCM.
 *   Written by Buffoni Mirko in 08/06/97
 *   References: various sources and documents.
 *
 *	 HJB 08/31/98
 *	 modified to use an automatically selected oversampling factor
 *	 for the current Machine->sample_rate
 */


#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "driver.h"
#include "adpcm.h"

#define OVERSAMPLING	0	/* breaks 10 Yard Fight */

/* signed/unsigned 8-bit conversion macros */
#ifdef SIGNED_SAMPLES
	#define AUDIO_CONV(A) ((A))
#else
	#define AUDIO_CONV(A) ((A)+0x80)
#endif

/* struct describing a single playing ADPCM voice */
struct ADPCMVoice
{
	int playing;            /* 1 if we are actively playing */
	int channel;            /* which channel are we playing on? */
	unsigned char *base;    /* pointer to the base memory location */
	unsigned char *stream;  /* input stream data (if any) */
	void *buffer;           /* output buffer (could be 8 or 16 bits) */
	int bufpos;             /* current position in the buffer */
	int mask;               /* mask to keep us within the buffer */
	int sample;             /* current sample number */
	int count;              /* total samples to play */
	int signal;             /* current ADPCM signal */
	int step;               /* current ADPCM step */
	int volume;             /* output volume */
};

/* global pointer to the current interface */
static struct ADPCMinterface *adpcm_intf;

/* global pointer to the current array of samples */
static struct ADPCMsample *sample_list;

/* array of ADPCM voices */
static struct ADPCMVoice adpcm[MAX_ADPCM];

/* sound channel info */
static int channel;

/* global buffer length and emulation output rate */
static int buffer_len;
static int emulation_rate;
#if OVERSAMPLING
static int oversampling;
#endif

/* step size index shift table */
static int index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };

/* lookup table for the precomputed difference */
static int diff_lookup[49*16];



/*
 *   Compute the difference table
 */

static void ComputeTables (void)
{
	/* nibble to bit map */
	static int nbl2bit[16][4] =
	{
		{ 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1},
		{ 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1},
		{-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1},
		{-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1}
	};

	int step, nib;

	/* loop over all possible steps */
	for (step = 0; step <= 48; step++)
	{
		/* compute the step value */
		int stepval = floor (16.0 * pow (11.0 / 10.0, (double)step));

		/* loop over all nibbles and compute the difference */
		for (nib = 0; nib < 16; nib++)
		{
			diff_lookup[step*16 + nib] = nbl2bit[nib][0] *
				(stepval   * nbl2bit[nib][1] +
				 stepval/2 * nbl2bit[nib][2] +
				 stepval/4 * nbl2bit[nib][3] +
				 stepval/8);
		}
	}
}



/*
 *   Start emulation of several ADPCM output streams
 */

int ADPCM_sh_start (struct ADPCMinterface *intf)
{
	int i;

	/* compute the difference tables */
	ComputeTables ();

	/* copy the interface pointer to a global */
	adpcm_intf = intf;

	/* set the default sample table */
	sample_list = (struct ADPCMsample *)Machine->gamedrv->sound_prom;

	/* if there's an init function, call it now to generate the table */
	if (intf->init)
	{
		sample_list = malloc (257 * sizeof (struct ADPCMsample));
		if (!sample_list)
			return 1;
		memset (sample_list, 0, 257 * sizeof (struct ADPCMsample));
		(*intf->init) (intf, sample_list, 256);
	}

	/* reserve sound channels */
	channel = get_play_channels (intf->num);

	/* compute the emulation rate and buffer size */
	buffer_len = intf->frequency / Machine->drv->frames_per_second;
    emulation_rate = buffer_len * Machine->drv->frames_per_second;

	/* initialize the voices */
	memset (adpcm, 0, sizeof (adpcm));
	for (i = 0; i < intf->num; i++)
	{
		adpcm[i].channel = channel + i;
		adpcm[i].mask = 0xffffffff;
		adpcm[i].signal = -2;
		adpcm[i].volume = intf->volume[i];

		/* allocate an output buffer */
		adpcm[i].buffer = malloc (buffer_len * Machine->sample_bits / 8);
		if (!adpcm[i].buffer)
			return 1;
	}

	/* success */
	return 0;
}



/*
 *   Stop emulation of several ADPCM output streams
 */

void ADPCM_sh_stop (void)
{
	int i;

	/* free the temporary table if we created it */
	if (sample_list && sample_list != (struct ADPCMsample *)Machine->gamedrv->sound_prom)
		free (sample_list);
	sample_list = 0;

	/* free any output and streaming buffers */
	for (i = 0; i < adpcm_intf->num; i++)
	{
		if (adpcm[i].stream)
			free (adpcm[i].stream);
		if (adpcm[i].buffer)
			free (adpcm[i].buffer);
	}
}



/*
 *   Update emulation of an ADPCM output stream
 */

static void ADPCM_update (struct ADPCMVoice *voice, int finalpos)
{
	int left = finalpos - voice->bufpos;

	/* see if there's actually any need to generate samples */
	if (left > 0)
	{
		/* if this voice is active */
		if (voice->playing)
		{
			unsigned char *base = voice->base;
			int sample = voice->sample;
			int signal = voice->signal;
			int count = voice->count;
			int step = voice->step;
			int mask = voice->mask;
			int val;
#if OVERSAMPLING
            int oldsignal = signal;
			int delta, i;
#endif

			/* 16-bit case */
			if (Machine->sample_bits == 16)
			{
				short *buffer = (short *)voice->buffer + voice->bufpos;

				while (left)
				{
					/* compute the new amplitude and update the current step */
					val = base[(sample / 2) & mask] >> (((sample & 1) << 2) ^ 4);
					signal += diff_lookup[step * 16 + (val & 15)];
					if (signal > 2047) signal = 2047;
					else if (signal < -2048) signal = -2048;
					step += index_shift[val & 7];
					if (step > 48) step = 48;
					else if (step < 0) step = 0;

#if OVERSAMPLING
                    /* antialiasing samples */
                    delta = signal - oldsignal;
					for (i = 1; left && i <= oversampling; left--, i++)
						*buffer++ = (oldsignal + delta * i / oversampling) * 16;
					oldsignal = signal;
#else
					*buffer++ = signal * 16;
					left--;
#endif

                    /* next! */
					if (++sample > count)
					{
						/* if we're not streaming, fill with silence and stop */
						if (voice->base != voice->stream)
						{
							while (left--)
								*buffer++ = 0;
							voice->playing = 0;
						}

						/* if we are streaming, pad with the last sample */
						else
						{
							short last = buffer[-1];
							while (left--)
								*buffer++ = last;
						}
						break;
					}
				}
			}

			/* 8-bit case */
			else
			{
				unsigned char *buffer = (unsigned char *)voice->buffer + voice->bufpos;

				while (left)
				{
					/* compute the new amplitude and update the current step */
					val = base[(sample / 2) & mask] >> (((sample & 1) << 2) ^ 4);
					signal += diff_lookup[step * 16 + (val & 15)];
					if (signal > 2047) signal = 2047;
					else if (signal < -2048) signal = -2048;
					step += index_shift[val & 7];
					if (step > 48) step = 48;
					else if (step < 0) step = 0;

#if OVERSAMPLING
                    delta = signal - oldsignal;
					for (i = 1; left && i <= oversampling; left--, i++)
						*buffer++ = AUDIO_CONV((oldsignal + delta * i / oversampling) / 16);
                    oldsignal = signal;
#else
					*buffer++ = AUDIO_CONV(signal / 16);
					left--;
#endif
                    /* next! */
					if (++sample > count)
					{
						/* if we're not streaming, fill with silence and stop */
						if (voice->base != voice->stream)
						{
							while (left--)
								*buffer++ = AUDIO_CONV (0);
							voice->playing = 0;
						}

						/* if we are streaming, pad with the last sample */
						else
						{
							unsigned char last = buffer[-1];
							while (left--)
								*buffer++ = last;
						}
						break;
					}
				}
			}

			/* update the parameters */
			voice->sample = sample;
			voice->signal = signal;
			voice->step = step;
		}

		/* voice is not playing */
		else
		{
			if (Machine->sample_bits == 16)
				memset ((short *)voice->buffer + voice->bufpos, 0, left * 2);
			else
				memset ((unsigned char *)voice->buffer + voice->bufpos, AUDIO_CONV (0), left);
		}

		/* update the final buffer position */
		voice->bufpos = finalpos;
	}
}



/*
 *   Update emulation of several ADPCM output streams
 */

void ADPCM_sh_update (void)
{
	int i;

	/* bail if we're not emulating sound */
	if (Machine->sample_rate == 0)
		return;

	/* loop over voices */
	for (i = 0; i < adpcm_intf->num; i++)
	{
		struct ADPCMVoice *voice = adpcm + i;

		/* update to the end of buffer */
		ADPCM_update (voice, buffer_len);

		/* play the result */
		if (Machine->sample_bits == 16)
			osd_play_streamed_sample_16 (voice->channel, voice->buffer, 2*buffer_len, emulation_rate, voice->volume,OSD_PAN_CENTER);
		else
			osd_play_streamed_sample (voice->channel, voice->buffer, buffer_len, emulation_rate, voice->volume,OSD_PAN_CENTER);

		/* reset the buffer position */
		voice->bufpos = 0;
	}
}



/*
 *   Handle a write to the ADPCM data stream
 */

void ADPCM_trigger (int num, int which)
{
	struct ADPCMVoice *voice = adpcm + num;
	struct ADPCMsample *sample;

	/* bail if we're not playing anything */
	if (Machine->sample_rate == 0)
		return;

	/* range check the numbers */
	if (num >= adpcm_intf->num)
	{
		return;
	}

	/* find a match */
	for (sample = sample_list; sample->length > 0; sample++)
	{
		if (sample->num == which)
		{
			/* update the ADPCM voice */
			ADPCM_update (voice, cpu_scalebyfcount (buffer_len));

			/* set up the voice to play this sample */
			voice->playing = 1;
			voice->base = &Machine->memory_region[adpcm_intf->region][sample->offset];
			voice->sample = 0;
			voice->count = sample->length;

			/* also reset the ADPCM parameters */
			voice->signal = -2;
			voice->step = 0;

			return;
		}
	}
}



void ADPCM_play (int num, int offset, int length)
{
	struct ADPCMVoice *voice = adpcm + num;


	/* bail if we're not playing anything */
	if (Machine->sample_rate == 0)
		return;

	/* range check the numbers */
	if (num >= adpcm_intf->num)
	{
		return;
	}

	/* update the ADPCM voice */
	ADPCM_update (voice, cpu_scalebyfcount (buffer_len));

	/* set up the voice to play this sample */
	voice->playing = 1;
	voice->base = &Machine->memory_region[adpcm_intf->region][offset];
	voice->sample = 0;
	voice->count = length;

	/* also reset the ADPCM parameters */
	voice->signal = -2;
	voice->step = 0;
}



⌨️ 快捷键说明

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