www.pudn.com > ngcd080s.zip > adpcm.c


/************************************** 
***      ADPCM decode routines      *** 
***---------------------------------***. 
*** Information from MAME project's *** 
***   fm.c by Tatsuyuki Satoh and   *** 
***        Hiromitsu Shioya         *** 
**************************************/ 
 
//-- Include Files ---------------------------------------------------------- 
#include  
#include "../sound/stream.h" 
#include "../ym2610/ym2610.h" 
#include "../z80/mz80.h" 
#include  
 
//-- Defines ---------------------------------------------------------------- 
#define NUM_BUFFERS	3 
#define BUFFER_SIZE 18500/60 
#define ADPCMA_VOLUME_RATE 1 
#define ADPCMA_DECODE_RANGE 1024 
#define ADPCMA_DECODE_MIN (-(ADPCMA_DECODE_RANGE*ADPCMA_VOLUME_RATE)) 
#define ADPCMA_DECODE_MAX ((ADPCMA_DECODE_RANGE*ADPCMA_VOLUME_RATE)-1) 
#define ADPCMB_DECODE_RANGE 32768 
#define ADPCMB_DECODE_MIN (-(ADPCMB_DECODE_RANGE)) 
#define ADPCMB_DECODE_MAX ((ADPCMB_DECODE_RANGE)-1) 
#define ADPCMB_DELTA_MAX (24576) 
#define ADPCMB_DELTA_MIN (127) 
#define ADPCMB_DELTA_DEF (127) 
#define AUDIO_CONV(a) (((a)&0x07FF)<<5) 
 
//-- Imported Variables ----------------------------------------------------- 
extern char *neogeo_pcm_memory; 
extern char *subcpu_memspace; 
 
//-- Structures ------------------------------------------------------------- 
typedef struct { 
	int	stream; 
	char	*start; 
	char	*end; 
	char	*ptr; 
	int	shift; 
	int	flag; 
	int	signal; 
	int	delta; 
	int	ch_val; 
	int	vol; 
	int	pan; 
	} ADPCM_CH; 
 
//-- Variables -------------------------------------------------------------- 
int	adpcmreg[2][0x30]; 
int	number = 0; 
int	adpcm_status = 0xBF; 
int	adpcm_statusmask = 0xBF; 
int	master_volumea = 32; 
ADPCM_CH	adpcm_ch[7]; 
 
//-- Private Variables ------------------------------------------------------ 
static short	decode_buffer[BUFFER_SIZE+1]; 
 
//-- Exported Functions ----------------------------------------------------- 
void	adpcm_init(void); 
int		adpcm_ch_init(ADPCM_CH *); 
void	adpcm_ch_play(ADPCM_CH *, char *, int, int, int, int); 
void	adpcm_ch_pause(ADPCM_CH *); 
void	adpcm_ch_resume(ADPCM_CH *); 
void	adpcm_ch_destroy(ADPCM_CH *); 
void	adpcm_ch_decodea(ADPCM_CH *); 
void	adpcm_ch_decodeb(ADPCM_CH *); 
void	adpcma_write(int Register, int Value); 
void	adpcmb_write(int Register, int Value); 
void	sound_mute(void); 
 
//-- Decode Tables ---------------------------------------------------------- 
static int	decode_tableA1[16] = { 
  -1*16, -1*16, -1*16, -1*16, 2*16, 5*16, 7*16, 9*16, 
  -1*16, -1*16, -1*16, -1*16, 2*16, 5*16, 7*16, 9*16 
}; 
static int	jedi_table[49*16]; 
 
static const int decode_tableB1[16] = { 
  1,   3,   5,   7,   9,  11,  13,  15, 
  -1,  -3,  -5,  -7,  -9, -11, -13, -15, 
}; 
 
static const int decode_tableB2[16] = { 
  57,  57,  57,  57, 77, 102, 128, 153, 
  57,  57,  57,  57, 77, 102, 128, 153 
}; 
 
#if 1 
#define decode_tableB3 decode_tableB1 
#else 
static const int decode_tableB3[16] = { 
  0, 2,  4,  6,  8,  10, 12, 14, 
  0,-2, -4, -6, -8, -10,-12,-14 
}; 
#endif 
 
// Limit output value 
inline void Limit(int *Value, int MaxVal, int MinVal) 
{ 
	if ((*Value)>MaxVal) 
		(*Value) = MaxVal; 
	else if ((*Value)stream = stream_create(18500); 
	if (ch->stream==-1) 
		return 0; 
	 
	/* Setup Default Values */ 
	ch->start = NULL; 
	ch->end = NULL; 
	ch->ptr = NULL; 
	ch->shift = 4; 
	ch->flag = 0; 
	ch->signal = 0; 
	ch->delta = 0; 
	 
	return 1; 
} 
 
//--------------------------------------------------------------------------- 
void	adpcm_ch_play(ADPCM_CH *ch, char *adpcm_buffer, int st, int ed, int vol, int pan) 
{ 
	if ((ch->flag&0xFFFFFFFE)==0) { 
		ch->start = adpcm_buffer + st; 
		ch->ptr = ch->start; 
		ch->end = adpcm_buffer + ed; 
		ch->shift = 4; 
		ch->flag = 1; 
		ch->signal = 0; 
		ch->delta = 0; 
		stream_adjust(ch->stream, vol, pan); 
	} 
} 
 
//--------------------------------------------------------------------------- 
void	adpcm_ch_pause(ADPCM_CH *ch) 
{ 
	/* Used to pause sound when in console mode, 
	   assumes there are no subsequent calls to adpcm_ch_decode until adpcm_ch_resume */ 
	    
	stream_pause(ch->stream); 
} 
 
//--------------------------------------------------------------------------- 
void	adpcm_ch_resume(ADPCM_CH *ch) 
{ 
	stream_resume(ch->stream); 
} 
 
//--------------------------------------------------------------------------- 
void	adpcm_ch_destroy(ADPCM_CH *ch) 
{ 
	stream_destroy(ch->stream); 
	ch->flag = -1; 
} 
 
//--------------------------------------------------------------------------- 
void	adpcm_ch_decodea(ADPCM_CH *ch) 
{ 
	register int	i; 
	int		smp; 
	short		*out; 
 
	out = &decode_buffer[0]; 
 
	for(i=BUFFER_SIZE;i>0;i--) { 
		if (ch->flag==1) { 
			smp = ((*(ch->ptr))>>(ch->shift))&0x0F; 
			if (ch->shift==0) { 
				ch->ptr++; 
				if (ch->ptr >= ch->end) 
				{ 
					adpcm_status |= ch->ch_val; 
					ch->flag = 0; 
				} 
			} 
			ch->shift ^= 4; 
			ch->signal += jedi_table[smp + ch->delta]; 
			ch->delta += decode_tableA1[smp]; 
			Limit(&(ch->signal), ADPCMA_DECODE_MAX, ADPCMA_DECODE_MIN); 
			Limit(&(ch->delta), 48*16, 0*16); 
			*(out++) = AUDIO_CONV(ch->signal); 
		} else { 
			ch->signal = 0; 
			*(out++) = AUDIO_CONV(ch->signal); 
		} 
	} 
	 
	stream_fill_buffer(ch->stream, (char *)(&decode_buffer[0])); 
} 
 
//--------------------------------------------------------------------------- 
void	sound_mute(void) 
{ 
	int	i, j; 
	 
	if (sound_device != 0) 
	{ 
		for(i=0;i0;i--) { 
		if (ch->flag==1) { 
			smp = ((*(ch->ptr))>>(ch->shift))&0x0F; 
			if (ch->shift==0) { 
				ch->ptr++; 
				if (ch->ptr >= ch->end) 
				{ 
					adpcm_status |= ch->ch_val; 
					ch->flag = 0; 
				} 
			} 
			ch->shift ^= 4; 
			ch->signal += ( decode_tableB1[smp] * ch->delta / 8 ); 
			ch->delta += ( ch->delta * decode_tableB2[smp] / 64 ); 
			Limit(&(ch->signal), ADPCMB_DECODE_MAX, ADPCMB_DECODE_MIN); 
			Limit(&(ch->delta), ADPCMB_DELTA_MAX, ADPCMB_DELTA_MIN); 
			*(out++) = ch->signal; 
		} else { 
			ch->signal = 0; 
			*(out++) = ch->signal; 
		} 
	} 
	 
	stream_fill_buffer(ch->stream, (char *)(&decode_buffer[0])); 
} 
 
//--------------------------------------------------------------------------- 
void	adpcma_write(int Register, int Value) 
{ 
	int	Channel = Register & 0x07; 
	 
	adpcmreg[1][Register] = Value & 0xFF; 
	 
	switch(Register) 
	{ 
	case 0x00: 
		port1state = Value & 0xFF; 
		 
		if (!(Value & 0x80)) 
		{ 
			for(Channel=0;Channel<6;Channel++) 
			{ 
				if (Value & (1<= 6) 
			return; 
		 
		switch(Register & 0x38) 
		{ 
		case	0x08: 
			adpcm_ch[Channel].vol = Value & 0x1F; 
			 
			switch(Value & 0xC0) 
			{ 
			case	0xC0: 
				adpcm_ch[Channel].pan = 128; 
				break; 
				 
			case	0x80: 
				adpcm_ch[Channel].pan = 255; 
				break; 
			 
			case	0x40: 
				adpcm_ch[Channel].pan = 0; 
				break; 
			} 
 
			stream_adjust(adpcm_ch[Channel].stream, master_volumea + adpcm_ch[Channel].vol, adpcm_ch[Channel].pan); 
			 
			break; 
		 
		case	0x10: 
		case	0x18: 
			adpcm_ch[Channel].start = (((adpcmreg[1][0x18 + Channel] * 0x0100 | adpcmreg[1][0x10 + Channel]) << port1shift) & 0xFFFFF) + neogeo_pcm_memory; 
			break; 
		 
		case	0x20: 
		case	0x28: 
			adpcm_ch[Channel].end = ((((adpcmreg[1][0x28 + Channel] * 0x0100 | adpcmreg[1][0x20 + Channel]) << port1shift) + ((1<> 2; 
		stream_adjust(adpcm_ch[6].stream, adpcm_ch[6].vol, adpcm_ch[6].pan); 
		break; 
	} 
}