2013-09-28 03:24:46 +00:00
/*********************************************************
Konami 053260 PCM Sound Chip
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "mamedef.h"
//#include "emu.h"
# ifdef _DEBUG
# include <stdio.h>
# endif
# include <stdlib.h>
# include <memory.h>
# include "k053260.h"
# define NULL ((void *)0)
/* 2004-02-28: Fixed PPCM decoding. Games sound much better now.*/
# define LOG 0
# define BASE_SHIFT 16
typedef struct _k053260_channel k053260_channel ;
struct _k053260_channel
{
UINT32 rate ;
UINT32 size ;
UINT32 start ;
UINT32 bank ;
UINT32 volume ;
int play ;
UINT32 pan ;
UINT32 pos ;
int loop ;
int ppcm ; /* packed PCM ( 4 bit signed ) */
int ppcm_data ;
UINT8 Muted ;
} ;
typedef struct _k053260_state k053260_state ;
struct _k053260_state
{
//sound_stream * channel;
int mode ;
int regs [ 0x30 ] ;
UINT8 * rom ;
//int rom_size;
UINT32 rom_size ;
UINT32 * delta_table ;
k053260_channel channels [ 4 ] ;
//const k053260_interface *intf;
//device_t *device;
} ;
/*INLINE k053260_state *get_safe_token(device_t *device)
{
assert ( device ! = NULL ) ;
assert ( device - > type ( ) = = K053260 ) ;
return ( k053260_state * ) downcast < legacy_device_base * > ( device ) - > token ( ) ;
} */
static void InitDeltaTable ( k053260_state * ic , int rate , int clock )
{
int i ;
double base = ( double ) rate ;
double max = ( double ) ( clock ) ; /* Hz */
UINT32 val ;
for ( i = 0 ; i < 0x1000 ; i + + ) {
double v = ( double ) ( 0x1000 - i ) ;
double target = ( max ) / v ;
double fixed = ( double ) ( 1 < < BASE_SHIFT ) ;
if ( target & & base ) {
target = fixed / ( base / target ) ;
val = ( UINT32 ) target ;
if ( val = = 0 )
val = 1 ;
} else
val = 1 ;
ic - > delta_table [ i ] = val ;
}
}
//static DEVICE_RESET( k053260 )
void device_reset_k053260 ( void * chip )
{
//k053260_state *ic = get_safe_token(device);
k053260_state * ic = ( k053260_state * ) chip ;
int i ;
for ( i = 0 ; i < 4 ; i + + ) {
ic - > channels [ i ] . rate = 0 ;
ic - > channels [ i ] . size = 0 ;
ic - > channels [ i ] . start = 0 ;
ic - > channels [ i ] . bank = 0 ;
ic - > channels [ i ] . volume = 0 ;
ic - > channels [ i ] . play = 0 ;
ic - > channels [ i ] . pan = 0 ;
ic - > channels [ i ] . pos = 0 ;
ic - > channels [ i ] . loop = 0 ;
ic - > channels [ i ] . ppcm = 0 ;
ic - > channels [ i ] . ppcm_data = 0 ;
}
}
INLINE int limit ( int val , int max , int min )
{
if ( val > max )
val = max ;
else if ( val < min )
val = min ;
return val ;
}
//#define MAXOUT 0x7fff
# define MAXOUT +0x8000
# define MINOUT -0x8000
//static STREAM_UPDATE( k053260_update )
void k053260_update ( void * chip , stream_sample_t * * outputs , int samples )
{
static const long dpcmcnv [ ] = { 0 , 1 , 2 , 4 , 8 , 16 , 32 , 64 , - 128 , - 64 , - 32 , - 16 , - 8 , - 4 , - 2 , - 1 } ;
int i , j , lvol [ 4 ] , rvol [ 4 ] , play [ 4 ] , loop [ 4 ] , ppcm_data [ 4 ] , ppcm [ 4 ] ;
unsigned char * rom [ 4 ] ;
UINT32 delta [ 4 ] , end [ 4 ] , pos [ 4 ] ;
int dataL , dataR ;
signed char d ;
k053260_state * ic = ( k053260_state * ) chip ;
/* precache some values */
for ( i = 0 ; i < 4 ; i + + ) {
rom [ i ] = & ic - > rom [ ic - > channels [ i ] . start + ( ic - > channels [ i ] . bank < < 16 ) ] ;
delta [ i ] = ic - > delta_table [ ic - > channels [ i ] . rate ] ;
lvol [ i ] = ic - > channels [ i ] . volume * ic - > channels [ i ] . pan ;
rvol [ i ] = ic - > channels [ i ] . volume * ( 8 - ic - > channels [ i ] . pan ) ;
end [ i ] = ic - > channels [ i ] . size ;
pos [ i ] = ic - > channels [ i ] . pos ;
play [ i ] = ic - > channels [ i ] . play ;
loop [ i ] = ic - > channels [ i ] . loop ;
ppcm [ i ] = ic - > channels [ i ] . ppcm ;
ppcm_data [ i ] = ic - > channels [ i ] . ppcm_data ;
if ( ppcm [ i ] )
delta [ i ] / = 2 ;
}
for ( j = 0 ; j < samples ; j + + ) {
dataL = dataR = 0 ;
for ( i = 0 ; i < 4 ; i + + ) {
/* see if the voice is on */
if ( play [ i ] ) {
/* see if we're done */
if ( ( pos [ i ] > > BASE_SHIFT ) > = end [ i ] ) {
ppcm_data [ i ] = 0 ;
if ( loop [ i ] )
pos [ i ] = 0 ;
else {
play [ i ] = 0 ;
continue ;
}
}
if ( ppcm [ i ] ) { /* Packed PCM */
/* we only update the signal if we're starting or a real sound sample has gone by */
/* this is all due to the dynamic sample rate convertion */
if ( pos [ i ] = = 0 | | ( ( pos [ i ] ^ ( pos [ i ] - delta [ i ] ) ) & 0x8000 ) = = 0x8000 )
{
int newdata ;
if ( pos [ i ] & 0x8000 ) {
newdata = ( ( rom [ i ] [ pos [ i ] > > BASE_SHIFT ] ) > > 4 ) & 0x0f ; /*high nybble*/
}
else {
newdata = ( ( rom [ i ] [ pos [ i ] > > BASE_SHIFT ] ) ) & 0x0f ; /*low nybble*/
}
ppcm_data [ i ] = ( ( ( ppcm_data [ i ] * 62 ) > > 6 ) + dpcmcnv [ newdata ] ) ;
if ( ppcm_data [ i ] > 127 )
ppcm_data [ i ] = 127 ;
else
if ( ppcm_data [ i ] < - 128 )
ppcm_data [ i ] = - 128 ;
}
d = ppcm_data [ i ] ;
pos [ i ] + = delta [ i ] ;
} else { /* PCM */
d = rom [ i ] [ pos [ i ] > > BASE_SHIFT ] ;
pos [ i ] + = delta [ i ] ;
}
if ( ic - > mode & 2 ) {
dataL + = ( d * lvol [ i ] ) > > 2 ;
dataR + = ( d * rvol [ i ] ) > > 2 ;
}
}
}
outputs [ 1 ] [ j ] = limit ( dataL , MAXOUT , MINOUT ) ;
outputs [ 0 ] [ j ] = limit ( dataR , MAXOUT , MINOUT ) ;
}
/* update the regs now */
for ( i = 0 ; i < 4 ; i + + ) {
ic - > channels [ i ] . pos = pos [ i ] ;
ic - > channels [ i ] . play = play [ i ] ;
ic - > channels [ i ] . ppcm_data = ppcm_data [ i ] ;
}
}
//static DEVICE_START( k053260 )
void * device_start_k053260 ( int clock )
{
//static const k053260_interface defintrf = { 0 };
//k053260_state *ic = get_safe_token(device);
k053260_state * ic ;
//int rate = device->clock() / 32;
int rate = clock / 32 ;
int i ;
ic = ( k053260_state * ) calloc ( 1 , sizeof ( k053260_state ) ) ;
/* Initialize our chip structure */
//ic->device = device;
//ic->intf = (device->static_config() != NULL) ? (const k053260_interface *)device->static_config() : &defintrf;
ic - > mode = 0 ;
//const memory_region *region = (ic->intf->rgnoverride != NULL) ? device->machine().region(ic->intf->rgnoverride) : device->region();
//ic->rom = *region;
//ic->rom_size = region->bytes();
ic - > rom = NULL ;
ic - > rom_size = 0x00 ;
// has to be done by the player after calling device_start
//DEVICE_RESET_CALL(k053260);
for ( i = 0 ; i < 0x30 ; i + + )
ic - > regs [ i ] = 0 ;
//ic->delta_table = auto_alloc_array( device->machine(), UINT32, 0x1000 );
ic - > delta_table = ( UINT32 * ) malloc ( 0x1000 * sizeof ( UINT32 ) ) ;
//ic->channel = device->machine().sound().stream_alloc( *device, 0, 2, rate, ic, k053260_update );
//InitDeltaTable( ic, rate, device->clock() );
InitDeltaTable ( ic , rate , clock ) ;
/* register with the save state system */
/*device->save_item(NAME(ic->mode));
device - > save_item ( NAME ( ic - > regs ) ) ;
for ( i = 0 ; i < 4 ; i + + )
{
device - > save_item ( NAME ( ic - > channels [ i ] . rate ) , i ) ;
device - > save_item ( NAME ( ic - > channels [ i ] . size ) , i ) ;
device - > save_item ( NAME ( ic - > channels [ i ] . start ) , i ) ;
device - > save_item ( NAME ( ic - > channels [ i ] . bank ) , i ) ;
device - > save_item ( NAME ( ic - > channels [ i ] . volume ) , i ) ;
device - > save_item ( NAME ( ic - > channels [ i ] . play ) , i ) ;
device - > save_item ( NAME ( ic - > channels [ i ] . pan ) , i ) ;
device - > save_item ( NAME ( ic - > channels [ i ] . pos ) , i ) ;
device - > save_item ( NAME ( ic - > channels [ i ] . loop ) , i ) ;
device - > save_item ( NAME ( ic - > channels [ i ] . ppcm ) , i ) ;
device - > save_item ( NAME ( ic - > channels [ i ] . ppcm_data ) , i ) ;
} */
/* setup SH1 timer if necessary */
//if ( ic->intf->irq )
// device->machine().scheduler().timer_pulse( attotime::from_hz(device->clock()) * 32, ic->intf->irq, "ic->intf->irq" );
return ic ; //return rate;
}
void device_stop_k053260 ( void * chip )
{
k053260_state * ic = ( k053260_state * ) chip ;
free ( ic - > delta_table ) ;
free ( ic - > rom ) ; ic - > rom = NULL ;
free ( ic ) ;
}
INLINE void check_bounds ( k053260_state * ic , int channel )
{
UINT32 channel_start = ( ic - > channels [ channel ] . bank < < 16 ) + ic - > channels [ channel ] . start ;
UINT32 channel_end = channel_start + ic - > channels [ channel ] . size - 1 ;
if ( channel_start > ic - > rom_size ) {
2013-10-03 08:00:58 +00:00
/*logerror("K53260: Attempting to start playing past the end of the ROM ( start = %06x, end = %06x ).\n", channel_start, channel_end );*/
2013-09-28 03:24:46 +00:00
ic - > channels [ channel ] . play = 0 ;
return ;
}
if ( channel_end > ic - > rom_size ) {
2013-10-03 08:00:58 +00:00
/*logerror("K53260: Attempting to play past the end of the ROM ( start = %06x, end = %06x ).\n", channel_start, channel_end );*/
2013-09-28 03:24:46 +00:00
ic - > channels [ channel ] . size = ic - > rom_size - channel_start ;
}
2013-10-03 08:00:58 +00:00
/*if (LOG) logerror("K053260: Sample Start = %06x, Sample End = %06x, Sample rate = %04x, PPCM = %s\n", channel_start, channel_end, ic->channels[channel].rate, ic->channels[channel].ppcm ? "yes" : "no" );*/
2013-09-28 03:24:46 +00:00
}
//WRITE8_DEVICE_HANDLER( k053260_w )
void k053260_w ( void * chip , offs_t offset , UINT8 data )
{
int i , t ;
int r = offset ;
int v = data ;
k053260_state * ic = ( k053260_state * ) chip ;
if ( r > 0x2f ) {
2013-10-03 08:00:58 +00:00
/*logerror("K053260: Writing past registers\n" );*/
2013-09-28 03:24:46 +00:00
return ;
}
//ic->channel->update();
/* before we update the regs, we need to check for a latched reg */
if ( r = = 0x28 ) {
t = ic - > regs [ r ] ^ v ;
for ( i = 0 ; i < 4 ; i + + ) {
if ( t & ( 1 < < i ) ) {
if ( v & ( 1 < < i ) ) {
ic - > channels [ i ] . play = 1 ;
ic - > channels [ i ] . pos = 0 ;
ic - > channels [ i ] . ppcm_data = 0 ;
check_bounds ( ic , i ) ;
} else
ic - > channels [ i ] . play = 0 ;
}
}
ic - > regs [ r ] = v ;
return ;
}
/* update regs */
ic - > regs [ r ] = v ;
/* communication registers */
if ( r < 8 )
return ;
/* channel setup */
if ( r < 0x28 ) {
int channel = ( r - 8 ) / 8 ;
switch ( ( r - 8 ) & 0x07 ) {
case 0 : /* sample rate low */
ic - > channels [ channel ] . rate & = 0x0f00 ;
ic - > channels [ channel ] . rate | = v ;
break ;
case 1 : /* sample rate high */
ic - > channels [ channel ] . rate & = 0x00ff ;
ic - > channels [ channel ] . rate | = ( v & 0x0f ) < < 8 ;
break ;
case 2 : /* size low */
ic - > channels [ channel ] . size & = 0xff00 ;
ic - > channels [ channel ] . size | = v ;
break ;
case 3 : /* size high */
ic - > channels [ channel ] . size & = 0x00ff ;
ic - > channels [ channel ] . size | = v < < 8 ;
break ;
case 4 : /* start low */
ic - > channels [ channel ] . start & = 0xff00 ;
ic - > channels [ channel ] . start | = v ;
break ;
case 5 : /* start high */
ic - > channels [ channel ] . start & = 0x00ff ;
ic - > channels [ channel ] . start | = v < < 8 ;
break ;
case 6 : /* bank */
ic - > channels [ channel ] . bank = v & 0xff ;
break ;
case 7 : /* volume is 7 bits. Convert to 8 bits now. */
ic - > channels [ channel ] . volume = ( ( v & 0x7f ) < < 1 ) | ( v & 1 ) ;
break ;
}
return ;
}
switch ( r ) {
case 0x2a : /* loop, ppcm */
for ( i = 0 ; i < 4 ; i + + )
ic - > channels [ i ] . loop = ( v & ( 1 < < i ) ) ! = 0 ;
for ( i = 4 ; i < 8 ; i + + )
ic - > channels [ i - 4 ] . ppcm = ( v & ( 1 < < i ) ) ! = 0 ;
break ;
case 0x2c : /* pan */
ic - > channels [ 0 ] . pan = v & 7 ;
ic - > channels [ 1 ] . pan = ( v > > 3 ) & 7 ;
break ;
case 0x2d : /* more pan */
ic - > channels [ 2 ] . pan = v & 7 ;
ic - > channels [ 3 ] . pan = ( v > > 3 ) & 7 ;
break ;
case 0x2f : /* control */
ic - > mode = v & 7 ;
/* bit 0 = read ROM */
/* bit 1 = enable sound output */
/* bit 2 = unknown */
break ;
}
}
//READ8_DEVICE_HANDLER( k053260_r )
UINT8 k053260_r ( void * chip , offs_t offset )
{
k053260_state * ic = ( k053260_state * ) chip ;
switch ( offset ) {
case 0x29 : /* channel status */
{
int i , status = 0 ;
for ( i = 0 ; i < 4 ; i + + )
status | = ic - > channels [ i ] . play < < i ;
return status ;
}
break ;
case 0x2e : /* read ROM */
if ( ic - > mode & 1 )
{
UINT32 offs = ic - > channels [ 0 ] . start + ( ic - > channels [ 0 ] . pos > > BASE_SHIFT ) + ( ic - > channels [ 0 ] . bank < < 16 ) ;
ic - > channels [ 0 ] . pos + = ( 1 < < 16 ) ;
if ( offs > ic - > rom_size ) {
//logerror("%s: K53260: Attempting to read past ROM size in ROM Read Mode (offs = %06x, size = %06x).\n", device->machine().describe_context(),offs,ic->rom_size );
2013-10-03 08:00:58 +00:00
/*logerror("K53260: Attempting to read past ROM size in ROM Read Mode (offs = %06x, size = %06x).\n", offs,ic->rom_size );*/
2013-09-28 03:24:46 +00:00
return 0 ;
}
return ic - > rom [ offs ] ;
}
break ;
}
return ic - > regs [ offset ] ;
}
void k053260_write_rom ( void * chip , offs_t ROMSize , offs_t DataStart , offs_t DataLength ,
const UINT8 * ROMData )
{
k053260_state * info = ( k053260_state * ) chip ;
if ( info - > rom_size ! = ROMSize )
{
info - > rom = ( UINT8 * ) realloc ( info - > rom , ROMSize ) ;
info - > rom_size = ROMSize ;
memset ( info - > rom , 0xFF , ROMSize ) ;
}
if ( DataStart > ROMSize )
return ;
if ( DataStart + DataLength > ROMSize )
DataLength = ROMSize - DataStart ;
memcpy ( info - > rom + DataStart , ROMData , DataLength ) ;
return ;
}
void k053260_set_mute_mask ( void * chip , UINT32 MuteMask )
{
k053260_state * info = ( k053260_state * ) chip ;
UINT8 CurChn ;
for ( CurChn = 0 ; CurChn < 4 ; CurChn + + )
info - > channels [ CurChn ] . Muted = ( MuteMask > > CurChn ) & 0x01 ;
}