mirror of
https://github.com/libretro/mame2003-plus-libretro.git
synced 2024-11-23 16:29:44 +00:00
Add files via upload
This commit is contained in:
parent
643c9bcf73
commit
98944d3c0a
@ -3,260 +3,268 @@
|
||||
/*********************************************************/
|
||||
|
||||
#include "driver.h"
|
||||
#include "rf5c68.h"
|
||||
#include <math.h>
|
||||
|
||||
#define PCM_NORMALIZE
|
||||
|
||||
#define NUM_CHANNELS (8)
|
||||
|
||||
|
||||
struct pcm_channel
|
||||
enum
|
||||
{
|
||||
UINT8 enable;
|
||||
UINT8 env;
|
||||
UINT8 pan;
|
||||
UINT8 start;
|
||||
UINT32 addr;
|
||||
UINT16 step;
|
||||
UINT16 loopst;
|
||||
RF_L_PAN = 0, RF_R_PAN = 1, RF_LR_PAN = 2
|
||||
};
|
||||
|
||||
static RF5C68PCM rpcm;
|
||||
static int reg_port;
|
||||
static int emulation_rate;
|
||||
|
||||
struct rf5c68pcm
|
||||
{
|
||||
sound_stream * stream;
|
||||
struct pcm_channel chan[NUM_CHANNELS];
|
||||
UINT8 cbank;
|
||||
UINT8 wbank;
|
||||
UINT8 enable;
|
||||
UINT8 data[0x10000];
|
||||
};
|
||||
static int buffer_len;
|
||||
static int stream;
|
||||
|
||||
/*static unsigned char pcmbuf[0x10000]; */
|
||||
static unsigned char *pcmbuf=NULL;
|
||||
|
||||
static struct RF5C68interface *intf;
|
||||
|
||||
static unsigned char wreg[0x10]; /* write data */
|
||||
|
||||
#define BASE_SHIFT (11+4)
|
||||
|
||||
#define RF_ON (1<<0)
|
||||
#define RF_START (1<<1)
|
||||
|
||||
|
||||
|
||||
/************************************************/
|
||||
/* RF5C68 stream update */
|
||||
/************************************************/
|
||||
|
||||
static void rf5c68_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length)
|
||||
{
|
||||
struct rf5c68pcm *chip = param;
|
||||
stream_sample_t *left = buffer[0];
|
||||
stream_sample_t *right = buffer[1];
|
||||
int i, j;
|
||||
|
||||
/* start with clean buffers */
|
||||
memset(left, 0, length * sizeof(*left));
|
||||
memset(right, 0, length * sizeof(*right));
|
||||
|
||||
/* bail if not enabled */
|
||||
if (!chip->enable)
|
||||
return;
|
||||
|
||||
/* loop over channels */
|
||||
for (i = 0; i < NUM_CHANNELS; i++)
|
||||
{
|
||||
struct pcm_channel *chan = &chip->chan[i];
|
||||
|
||||
/* if this channel is active, accumulate samples */
|
||||
if (chan->enable)
|
||||
{
|
||||
int lv = (chan->pan & 0x0f) * chan->env;
|
||||
int rv = ((chan->pan >> 4) & 0x0f) * chan->env;
|
||||
|
||||
/* loop over the sample buffer */
|
||||
for (j = 0; j < length; j++)
|
||||
{
|
||||
int sample;
|
||||
|
||||
/* fetch the sample and handle looping */
|
||||
sample = chip->data[(chan->addr >> 11) & 0xffff];
|
||||
if (sample == 0xff)
|
||||
{
|
||||
chan->addr = chan->loopst << 11;
|
||||
sample = chip->data[(chan->addr >> 11) & 0xffff];
|
||||
|
||||
/* if we loop to a loop point, we're effectively dead */
|
||||
if (sample == 0xff)
|
||||
break;
|
||||
}
|
||||
chan->addr += chan->step;
|
||||
|
||||
/* add to the buffer */
|
||||
if (sample & 0x80)
|
||||
{
|
||||
sample &= 0x7f;
|
||||
left[j] += (sample * lv) >> 5;
|
||||
right[j] += (sample * rv) >> 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
left[j] -= (sample * lv) >> 5;
|
||||
right[j] -= (sample * rv) >> 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* now clamp and shift the result (output is only 10 bits) */
|
||||
for (j = 0; j < length; j++)
|
||||
{
|
||||
stream_sample_t temp;
|
||||
|
||||
temp = left[j];
|
||||
if (temp > 32767) temp = 32767;
|
||||
else if (temp < -32768) temp = -32768;
|
||||
left[j] = temp & ~0x3f;
|
||||
|
||||
temp = right[j];
|
||||
if (temp > 32767) temp = 32767;
|
||||
else if (temp < -32768) temp = -32768;
|
||||
right[j] = temp & ~0x3f;
|
||||
}
|
||||
}
|
||||
|
||||
static void RF5C68Update( int num, INT16 **buffer, int length );
|
||||
|
||||
/************************************************/
|
||||
/* RF5C68 start */
|
||||
/************************************************/
|
||||
|
||||
static void *rf5c68_start(int sndindex, int clock, const void *config)
|
||||
int RF5C68_sh_start( const struct MachineSound *msound )
|
||||
{
|
||||
/* allocate memory for the chip */
|
||||
struct rf5c68pcm *chip = auto_malloc(sizeof(*chip));
|
||||
memset(chip, 0, sizeof(*chip));
|
||||
int i;
|
||||
int rate = Machine->sample_rate;
|
||||
struct RF5C68interface *inintf = msound->sound_interface;
|
||||
|
||||
/* skip if no sound */
|
||||
if (Machine->sample_rate == 0)
|
||||
if (Machine->sample_rate == 0) return 0;
|
||||
|
||||
if(pcmbuf==NULL) pcmbuf=(unsigned char *)malloc(0x10000);
|
||||
if(pcmbuf==NULL) return 1;
|
||||
|
||||
memset(pcmbuf, 0xff, 0x10000);
|
||||
|
||||
intf = inintf;
|
||||
buffer_len = rate / Machine->drv->frames_per_second;
|
||||
emulation_rate = buffer_len * Machine->drv->frames_per_second;
|
||||
|
||||
rpcm.clock = intf->clock;
|
||||
for( i = 0; i < RF5C68_PCM_MAX; i++ )
|
||||
{
|
||||
rpcm.env[i] = 0;
|
||||
rpcm.pan[i] = 0;
|
||||
rpcm.start[i] = 0;
|
||||
rpcm.step[i] = 0;
|
||||
rpcm.flag[i] = 0;
|
||||
}
|
||||
for( i = 0; i < 0x10; i++ ) wreg[i] = 0;
|
||||
reg_port = 0;
|
||||
|
||||
{
|
||||
char buf[2][40];
|
||||
const char *name[2];
|
||||
int vol[2];
|
||||
name[0] = buf[0];
|
||||
name[1] = buf[1];
|
||||
sprintf( buf[0], "%s Left", sound_name(msound) );
|
||||
sprintf( buf[1], "%s Right", sound_name(msound) );
|
||||
vol[0] = (MIXER_PAN_LEFT<<8) | (intf->volume&0xff);
|
||||
vol[1] = (MIXER_PAN_RIGHT<<8) | (intf->volume&0xff);
|
||||
|
||||
stream = stream_init_multi( RF_LR_PAN, name, vol, rate, 0, RF5C68Update );
|
||||
if(stream == -1) return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
/* allocate the stream */
|
||||
chip->stream = stream_create(0, 2, clock / 384, chip, rf5c68_update);
|
||||
return chip;
|
||||
}
|
||||
|
||||
/************************************************/
|
||||
/* RF5C68 stop */
|
||||
/************************************************/
|
||||
void RF5C68_sh_stop( void )
|
||||
{
|
||||
if(pcmbuf!=NULL) free(pcmbuf);
|
||||
pcmbuf=NULL;
|
||||
}
|
||||
|
||||
/************************************************/
|
||||
/* RF5C68 update */
|
||||
/************************************************/
|
||||
|
||||
static INLINE int ILimit(int v, int max, int min) { return v > max ? max : (v < min ? min : v); }
|
||||
|
||||
static void RF5C68Update( int num, INT16 **buffer, int length )
|
||||
{
|
||||
int i, j, tmp;
|
||||
unsigned int addr, old_addr;
|
||||
signed int ld, rd;
|
||||
INT16 *datap[2];
|
||||
|
||||
datap[RF_L_PAN] = buffer[0];
|
||||
datap[RF_R_PAN] = buffer[1];
|
||||
|
||||
memset( datap[RF_L_PAN], 0x00, length * sizeof(INT16) );
|
||||
memset( datap[RF_R_PAN], 0x00, length * sizeof(INT16) );
|
||||
|
||||
for( i = 0; i < RF5C68_PCM_MAX; i++ )
|
||||
{
|
||||
if( (rpcm.flag[i]&(RF_START|RF_ON)) == (RF_START|RF_ON) )
|
||||
{
|
||||
/**** PCM setup ****/
|
||||
addr = (rpcm.addr[i]>>BASE_SHIFT)&0xffff;
|
||||
ld = (rpcm.pan[i]&0x0f);
|
||||
rd = ((rpcm.pan[i]>>4)&0x0f);
|
||||
/* cen = (ld + rd) / 4; */
|
||||
/* ld = (rpcm.env[i]&0xff) * (ld + cen); */
|
||||
/* rd = (rpcm.env[i]&0xff) * (rd + cen); */
|
||||
ld = (rpcm.env[i]&0xff) * ld;
|
||||
rd = (rpcm.env[i]&0xff) * rd;
|
||||
|
||||
for( j = 0; j < length; j++ )
|
||||
{
|
||||
old_addr = addr;
|
||||
addr = (rpcm.addr[i]>>BASE_SHIFT)&0xffff;
|
||||
for(; old_addr <= addr; old_addr++ )
|
||||
{
|
||||
/**** PCM end check ****/
|
||||
if( (((unsigned int)pcmbuf[old_addr])&0x00ff) == (unsigned int)0x00ff )
|
||||
{
|
||||
rpcm.addr[i] = rpcm.loop[i] + ((addr - old_addr)<<BASE_SHIFT);
|
||||
addr = (rpcm.addr[i]>>BASE_SHIFT)&0xffff;
|
||||
/**** PCM loop check ****/
|
||||
if( (((unsigned int)pcmbuf[addr])&0x00ff) == (unsigned int)0x00ff ) /* this causes looping problems */
|
||||
{
|
||||
rpcm.flag[i] = 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
old_addr = addr;
|
||||
}
|
||||
}
|
||||
#ifdef PCM_NORMALIZE
|
||||
tmp = rpcm.pcmd[i];
|
||||
rpcm.pcmd[i] = (pcmbuf[old_addr]&0x7f) * (-1 + (2 * ((pcmbuf[old_addr]>>7)&0x01)));
|
||||
rpcm.pcma[i] = (tmp - rpcm.pcmd[i]) / 2;
|
||||
rpcm.pcmd[i] += rpcm.pcma[i];
|
||||
#endif
|
||||
}
|
||||
rpcm.addr[i] += rpcm.step[i];
|
||||
if( !rpcm.flag[i] ) break; /* skip PCM */
|
||||
#ifndef PCM_NORMALIZE
|
||||
if( pcmbuf[addr]&0x80 )
|
||||
{
|
||||
rpcm.pcmx[0][i] = ((signed int)(pcmbuf[addr]&0x7f))*ld;
|
||||
rpcm.pcmx[1][i] = ((signed int)(pcmbuf[addr]&0x7f))*rd;
|
||||
}
|
||||
else
|
||||
{
|
||||
rpcm.pcmx[0][i] = ((signed int)(-(pcmbuf[addr]&0x7f)))*ld;
|
||||
rpcm.pcmx[1][i] = ((signed int)(-(pcmbuf[addr]&0x7f)))*rd;
|
||||
}
|
||||
#else
|
||||
rpcm.pcmx[0][i] = rpcm.pcmd[i] * ld;
|
||||
rpcm.pcmx[1][i] = rpcm.pcmd[i] * rd;
|
||||
#endif
|
||||
*(datap[RF_L_PAN] + j) = ILimit( ((int)*(datap[RF_L_PAN] + j) + ((rpcm.pcmx[0][i])>>4)), 32767, -32768 );
|
||||
*(datap[RF_R_PAN] + j) = ILimit( ((int)*(datap[RF_R_PAN] + j) + ((rpcm.pcmx[1][i])>>4)), 32767, -32768 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************/
|
||||
/* RF5C68 write register */
|
||||
/************************************************/
|
||||
|
||||
WRITE8_HANDLER( RF5C68_reg_w )
|
||||
WRITE_HANDLER( RF5C68_reg_w )
|
||||
{
|
||||
struct rf5c68pcm *chip = sndti_token(SOUND_RF5C68, 0);
|
||||
struct pcm_channel *chan = &chip->chan[chip->cbank];
|
||||
int i;
|
||||
int val;
|
||||
|
||||
/* force the stream to update first */
|
||||
stream_update(chip->stream, 0);
|
||||
wreg[offset] = data; /* stock write data */
|
||||
/**** set PCM registers ****/
|
||||
|
||||
/* switch off the address */
|
||||
switch (offset)
|
||||
switch( offset )
|
||||
{
|
||||
case 0x00: /* envelope */
|
||||
chan->env = data;
|
||||
case 0x00:
|
||||
rpcm.env[reg_port] = data; /* set env. */
|
||||
break;
|
||||
case 0x01:
|
||||
rpcm.pan[reg_port] = data; /* set pan */
|
||||
break;
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
/**** address step ****/
|
||||
val = (((((int)wreg[0x03])<<8)&0xff00) | (((int)wreg[0x02])&0x00ff));
|
||||
rpcm.step[reg_port] = (int)(
|
||||
(
|
||||
( 28456.0 / (float)emulation_rate ) *
|
||||
( val / (float)(0x0800) ) *
|
||||
(rpcm.clock / 8000000.0) *
|
||||
(1<<BASE_SHIFT)
|
||||
)
|
||||
);
|
||||
break;
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
/**** loop address ****/
|
||||
rpcm.loop[reg_port] = (((((unsigned int)wreg[0x05])<<8)&0xff00)|(((unsigned int)wreg[0x04])&0x00ff))<<(BASE_SHIFT);
|
||||
break;
|
||||
case 0x06:
|
||||
/**** start address ****/
|
||||
rpcm.start[reg_port] = (((unsigned int)wreg[0x06])&0x00ff)<<(BASE_SHIFT + 8);
|
||||
rpcm.addr[reg_port] = rpcm.start[reg_port];
|
||||
break;
|
||||
case 0x07:
|
||||
reg_port = wreg[0x07]&0x07;
|
||||
if( data&0x80 )
|
||||
{
|
||||
rpcm.pcmx[0][reg_port] = 0;
|
||||
rpcm.pcmx[1][reg_port] = 0;
|
||||
rpcm.flag[reg_port] |= RF_START;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x01: /* pan */
|
||||
chan->pan = data;
|
||||
break;
|
||||
|
||||
case 0x02: /* FDL */
|
||||
chan->step = (chan->step & 0xff00) | (data & 0x00ff);
|
||||
break;
|
||||
|
||||
case 0x03: /* FDH */
|
||||
chan->step = (chan->step & 0x00ff) | ((data << 8) & 0xff00);
|
||||
break;
|
||||
|
||||
case 0x04: /* LSL */
|
||||
chan->loopst = (chan->loopst & 0xff00) | (data & 0x00ff);
|
||||
break;
|
||||
|
||||
case 0x05: /* LSH */
|
||||
chan->loopst = (chan->loopst & 0x00ff) | ((data << 8) & 0xff00);
|
||||
break;
|
||||
|
||||
case 0x06: /* ST */
|
||||
chan->start = data;
|
||||
if (!chan->enable)
|
||||
chan->addr = chan->start << (8 + 11);
|
||||
break;
|
||||
|
||||
case 0x07: /* control reg */
|
||||
chip->enable = (data >> 7) & 1;
|
||||
if (data & 0x40)
|
||||
chip->cbank = data & 7;
|
||||
case 0x08:
|
||||
/**** pcm on/off ****/
|
||||
for( i = 0; i < RF5C68_PCM_MAX; i++ )
|
||||
{
|
||||
if( !(data&(1<<i)) )
|
||||
{
|
||||
rpcm.flag[i] |= RF_ON; /* PCM on */
|
||||
}
|
||||
else
|
||||
chip->wbank = data & 15;
|
||||
break;
|
||||
|
||||
case 0x08: /* channel on/off reg */
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
chip->chan[i].enable = (~data >> i) & 1;
|
||||
if (!chip->chan[i].enable)
|
||||
chip->chan[i].addr = chip->chan[i].start << (8 + 11);
|
||||
rpcm.flag[i] &= ~(RF_ON); /* PCM off */
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************************************/
|
||||
/* RF5C68 read memory */
|
||||
/************************************************/
|
||||
|
||||
READ8_HANDLER( RF5C68_r )
|
||||
READ_HANDLER( RF5C68_r )
|
||||
{
|
||||
struct rf5c68pcm *chip = sndti_token(SOUND_RF5C68, 0);
|
||||
return chip->data[chip->wbank * 0x1000 + offset];
|
||||
unsigned int bank;
|
||||
bank = wreg[0x7] & 0x40 ? rpcm.start[reg_port] >> BASE_SHIFT : (wreg[0x7] & 0xf) << 12;
|
||||
return pcmbuf[bank + offset];
|
||||
}
|
||||
|
||||
|
||||
/************************************************/
|
||||
/* RF5C68 write memory */
|
||||
/************************************************/
|
||||
|
||||
WRITE8_HANDLER( RF5C68_w )
|
||||
WRITE_HANDLER( RF5C68_w )
|
||||
{
|
||||
struct rf5c68pcm *chip = sndti_token(SOUND_RF5C68, 0);
|
||||
chip->data[chip->wbank * 0x1000 + offset] = data;
|
||||
unsigned int bank;
|
||||
bank = wreg[0x7] & 0x40 ? rpcm.start[reg_port] >> BASE_SHIFT : (wreg[0x7] & 0xf) << 12;
|
||||
pcmbuf[bank + offset] = data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Generic get_info
|
||||
**************************************************************************/
|
||||
|
||||
static void rf5c68_set_info(void *token, UINT32 state, union sndinfo *info)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
/* no parameters to set */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void rf5c68_get_info(void *token, UINT32 state, union sndinfo *info)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
||||
|
||||
/* --- the following bits of info are returned as pointers to data or functions --- */
|
||||
case SNDINFO_PTR_SET_INFO: info->set_info = rf5c68_set_info; break;
|
||||
case SNDINFO_PTR_START: info->start = rf5c68_start; break;
|
||||
case SNDINFO_PTR_STOP: /* Nothing */ break;
|
||||
case SNDINFO_PTR_RESET: /* Nothing */ break;
|
||||
|
||||
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
||||
case SNDINFO_STR_NAME: info->s = "RF5C68"; break;
|
||||
case SNDINFO_STR_CORE_FAMILY: info->s = "Ricoh PCM"; break;
|
||||
case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
|
||||
case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
|
||||
case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break;
|
||||
}
|
||||
}
|
||||
|
||||
/**************** end of file ****************/
|
||||
|
@ -5,10 +5,38 @@
|
||||
#define __RF5C68_H__
|
||||
|
||||
/******************************************/
|
||||
WRITE8_HANDLER( RF5C68_reg_w );
|
||||
#define RF5C68_PCM_MAX (8)
|
||||
|
||||
READ8_HANDLER( RF5C68_r );
|
||||
WRITE8_HANDLER( RF5C68_w );
|
||||
|
||||
typedef struct rf5c68pcm
|
||||
{
|
||||
int clock;
|
||||
unsigned char env[RF5C68_PCM_MAX];
|
||||
unsigned char pan[RF5C68_PCM_MAX];
|
||||
unsigned int addr[RF5C68_PCM_MAX];
|
||||
unsigned int start[RF5C68_PCM_MAX];
|
||||
unsigned int step[RF5C68_PCM_MAX];
|
||||
unsigned int loop[RF5C68_PCM_MAX];
|
||||
int pcmx[2][RF5C68_PCM_MAX];
|
||||
int flag[RF5C68_PCM_MAX];
|
||||
|
||||
int pcmd[RF5C68_PCM_MAX];
|
||||
int pcma[RF5C68_PCM_MAX];
|
||||
} RF5C68PCM;
|
||||
|
||||
struct RF5C68interface
|
||||
{
|
||||
int clock;
|
||||
int volume;
|
||||
};
|
||||
|
||||
/******************************************/
|
||||
int RF5C68_sh_start( const struct MachineSound *msound );
|
||||
void RF5C68_sh_stop( void );
|
||||
WRITE_HANDLER( RF5C68_reg_w );
|
||||
|
||||
READ_HANDLER( RF5C68_r );
|
||||
WRITE_HANDLER( RF5C68_w );
|
||||
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user