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;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 += ( 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; } }