Add and hook up ZOOM ZSG-2 skeleton [Olivier Galibert]

Doesn't do much at the moment, but the increase in documentation value is
significant (we're documenting the sample compression format, for one thing).
This commit is contained in:
R. Belmont 2010-02-07 04:59:42 +00:00
parent 1f76758746
commit 49e9851b24
6 changed files with 300 additions and 4 deletions

2
.gitattributes vendored
View File

@ -999,6 +999,8 @@ src/emu/sound/ymf278b.c svneol=native#text/plain
src/emu/sound/ymf278b.h svneol=native#text/plain
src/emu/sound/ymz280b.c svneol=native#text/plain
src/emu/sound/ymz280b.h svneol=native#text/plain
src/emu/sound/zsg2.c svneol=native#text/plain
src/emu/sound/zsg2.h svneol=native#text/plain
src/emu/state.c svneol=native#text/plain
src/emu/state.h svneol=native#text/plain
src/emu/streams.c svneol=native#text/plain

View File

@ -648,3 +648,12 @@ endif
ifneq ($(filter YMZ280B,$(SOUNDS)),)
SOUNDOBJS += $(SOUNDOBJ)/ymz280b.o
endif
#-------------------------------------------------
# ZOOM ZSG-2
#-------------------------------------------------
ifneq ($(filter ZSG2,$(SOUNDS)),)
SOUNDOBJS += $(SOUNDOBJ)/zsg2.o
endif

251
src/emu/sound/zsg2.c Normal file
View File

@ -0,0 +1,251 @@
/*
ZOOM ZSG-2 custom wavetable synthesizer
Written by Olivier Galibert
MAME conversion by R. Belmont
Copyright Nicola Salmoria and the MAME Team.
Visit http://mamedev.org for licensing and usage restrictions.
---------------------------------------------------------
Additional notes on the sample format, reverse-engineered
by Olivier Galibert and David Haywood:
The zoom sample rom is decomposed in 0x40000 bytes pages. Each page
starts by a header and is followed by compressed samples.
The header is a vector of 16 bytes structures composed of 4 32bits
little-endian values representing:
- sample start position in bytes, always a multiple of 4
- sample end position in bytes, minus 4, always...
- loop position in bytes, always....
- flags, probably
The samples are compressed with a 2:1 ratio. Each bloc of 4-bytes
becomes 4 16-bits samples. Reading the 4 bytes as a *little-endian*
32bits values, the structure is:
1444 4444 1333 3333 1222 2222 ssss1111
's' is a 4-bit scale value. '1', '2', '3', '4' are signed 7-bits
values corresponding to the 4 samples. To compute the final 16bits
value just shift left by (9-s). Yes, that simple.
*/
#include "emu.h"
#include "streams.h"
#include "zsg2.h"
typedef struct _zchan zchan;
struct _zchan
{
UINT16 v[16];
};
typedef struct _zsg2_state zsg2_state;
struct _zsg2_state
{
zchan zc[48];
UINT16 act[3];
UINT16 alow, ahigh;
UINT8 *bank_samples;
int sample_rate;
sound_stream *stream;
};
INLINE zsg2_state *get_safe_token(running_device *device)
{
assert(device != NULL);
assert(device->token != NULL);
assert(device->type == SOUND);
assert(sound_get_type(device) == SOUND_ZSG2);
return (zsg2_state *)device->token;
}
static STREAM_UPDATE( update_stereo )
{
// zsg2_state *info = (zsg2_state *)param;
stream_sample_t *dest1 = outputs[0];
stream_sample_t *dest2 = outputs[1];
memset(dest1, 0, sizeof(stream_sample_t) * samples);
memset(dest2, 0, sizeof(stream_sample_t) * samples);
}
static void chan_w(zsg2_state *info, int chan, int reg, UINT16 data)
{
info->zc[chan].v[reg] = data;
// log_event("ZOOMCHAN", "chan %02x reg %x = %04x", chan, reg, data);
}
static UINT16 chan_r(zsg2_state *info, int chan, int reg)
{
// log_event("ZOOMCHAN", "chan %02x read reg %x: %04x", chan, reg, zc[chan].v[reg]);
return info->zc[chan].v[reg];
}
static void check_channel(zsg2_state *info, int chan)
{
// log_event("ZOOM", "chan %02x e=%04x f=%04x", chan, zc[chan].v[14], zc[chan].v[15]);
}
static void keyon(zsg2_state *info, int chan)
{
#if 0
log_event("ZOOM", "keyon %02x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x",
chan,
info->zc[chan].v[0x0], info->zc[chan].v[0x1], info->zc[chan].v[0x2], info->zc[chan].v[0x3],
info->zc[chan].v[0x4], info->zc[chan].v[0x5], info->zc[chan].v[0x6], info->zc[chan].v[0x7],
info->zc[chan].v[0x8], info->zc[chan].v[0x9], info->zc[chan].v[0xa], info->zc[chan].v[0xb],
info->zc[chan].v[0xc], info->zc[chan].v[0xd], info->zc[chan].v[0xe], info->zc[chan].v[0xf]);
#endif
}
static void control_w(zsg2_state *info, int reg, UINT16 data)
{
switch(reg)
{
case 0x00: case 0x02: case 0x04:
{
int base = (reg & 6) << 3;
int i;
for(i=0; i<16; i++)
if(data & (1<<i))
keyon(info, base+i);
break;
}
case 0x08: case 0x0a: case 0x0c:
{
int base = (reg & 6) << 3;
int i;
for(i=0; i<16; i++)
if(data & (1<<i))
check_channel(info, base+i);
break;
}
case 0x30:
break;
case 0x38:
info->alow = data;
break;
case 0x3a:
info->ahigh = data;
break;
default:
// log_event("ZOOMCTRL", "%02x = %04x", reg, data);
break;
}
}
static UINT16 control_r(zsg2_state *info, int reg)
{
switch(reg)
{
case 0x28:
return 0xff00;
case 0x3c: case 0x3e:
{
UINT32 adr = (info->ahigh << 16) | info->alow;
UINT32 val = *(unsigned int *)(info->bank_samples+adr);
// log_event("ZOOMCTRL", "rom read.%c %06x = %08x", reg == 0x3e ? 'h' : 'l', adr, val);
return (reg == 0x3e) ? (val >> 16) : val;
}
}
// log_event("ZOOMCTRL", "read %02x", reg);
return 0xffff;
}
WRITE16_DEVICE_HANDLER( zsg2_w )
{
zsg2_state *info = get_safe_token(device);
int adr = offset * 2;
assert(mem_mask == 0xffff); // we only support full 16-bit accesses
stream_update(info->stream);
if (adr < 0x600)
{
int chan = adr >> 5;
int reg = (adr >> 1) & 15;
chan_w(info, chan, reg, data);
}
else
{
control_w(info, adr - 0x600, data);
}
}
READ16_DEVICE_HANDLER( zsg2_r )
{
zsg2_state *info = get_safe_token(device);
int adr = offset * 2;
assert(mem_mask == 0xffff); // we only support full 16-bit accesses
if (adr < 0x600)
{
int chan = adr >> 5;
int reg = (adr >> 1) & 15;
return chan_r(info, chan, reg);
}
else
{
return control_r(info, adr - 0x600);
}
return 0;
}
static DEVICE_START( zsg2 )
{
const zsg2_interface *intf = (const zsg2_interface *)device->baseconfig().static_config;
zsg2_state *info = get_safe_token(device);
info->sample_rate = device->clock;
memset(&info->zc, 0, sizeof(info->zc));
memset(&info->act, 0, sizeof(info->act));
info->stream = stream_create(device, 0, 2, info->sample_rate, info, update_stereo);
info->bank_samples = memory_region(device->machine, intf->samplergn);
}
/**************************************************************************
* Generic get_info
**************************************************************************/
DEVICE_GET_INFO( zsg2 )
{
switch (state)
{
/* --- the following bits of info are returned as 64-bit signed integers --- */
case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(zsg2_state); break;
/* --- the following bits of info are returned as pointers to data or functions --- */
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( zsg2 ); break;
case DEVINFO_FCT_STOP: /* nothing */ break;
case DEVINFO_FCT_RESET: /* nothing */ break;
/* --- the following bits of info are returned as NULL-terminated strings --- */
case DEVINFO_STR_NAME: strcpy(info->s, "ZSG-2"); break;
case DEVINFO_STR_FAMILY: strcpy(info->s, "Zoom custom"); break;
case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
}
}

22
src/emu/sound/zsg2.h Normal file
View File

@ -0,0 +1,22 @@
/*
ZOOM ZSG-2 custom wavetable synthesizer
*/
#pragma once
#ifndef __ZSG2_H__
#define __ZSG2_H__
READ16_DEVICE_HANDLER( zsg2_r );
WRITE16_DEVICE_HANDLER( zsg2_w );
typedef struct _zsg2_interface zsg2_interface;
struct _zsg2_interface
{
const char *samplergn;
};
DEVICE_GET_INFO( zsg2 );
#define SOUND_ZSG2 DEVICE_GET_INFO_NAME( zsg2 )
#endif /* __ZSG2_H__ */

View File

@ -1,7 +1,7 @@
/***************************************************************************
Taito Zoom ZSG-1 sound board
Includes: MN10200 CPU, ZOOM ZSG-1 audio chip, TMS57002 DASP
Taito Zoom ZSG-2 sound board
Includes: MN10200 CPU, ZOOM ZSG-2 audio chip, TMS57002 DASP
By Olivier Galibert.
Copyright Nicola Salmoria and the MAME Team.
@ -13,11 +13,12 @@
#include "cpu/mn10200/mn10200.h"
#include "cpu/tms57002/tms57002.h"
#include "audio/taito_zm.h"
#include "sound/zsg2.h"
static ADDRESS_MAP_START(taitozoom_map, ADDRESS_SPACE_PROGRAM, 16)
AM_RANGE(0x080000, 0x0fffff) AM_ROM AM_REGION("mn10200", 0)
AM_RANGE(0x400000, 0x40ffff) AM_RAM
AM_RANGE(0x800000, 0x800fff) AM_RAM // Zoom ZSG-1
AM_RANGE(0x800000, 0x800fff) AM_DEVREADWRITE("zsg2", zsg2_r, zsg2_w)
AM_RANGE(0xe00000, 0xe000ff) AM_RAM // main CPU comms?
AM_RANGE(0xc00000, 0xc00001) AM_RAM // TMS57002 comms
ADDRESS_MAP_END
@ -44,8 +45,19 @@ static ADDRESS_MAP_START(taitozoom_io_map, ADDRESS_SPACE_IO, 8)
AM_RANGE(MN10200_PORT1, MN10200_PORT1) AM_READWRITE(tms_ctrl_r, tms_ctrl_w)
ADDRESS_MAP_END
static const zsg2_interface zsg2_taito_config =
{
"zsg2" /* sample region */
};
MACHINE_DRIVER_START( taito_zoom_sound )
MDRV_CPU_ADD("mn10200", MN10200, 25000000/2)
MDRV_CPU_PROGRAM_MAP(taitozoom_map)
MDRV_CPU_IO_MAP(taitozoom_io_map)
// we assume the parent machine has created lspeaker/rspeaker
MDRV_SOUND_ADD("zsg2", ZSG2, 25000000/2)
MDRV_SOUND_CONFIG(zsg2_taito_config)
MDRV_SOUND_ROUTE(0, "lspeaker", 1.0)
MDRV_SOUND_ROUTE(1, "rspeaker", 1.0)
MACHINE_DRIVER_END

View File

@ -220,7 +220,7 @@ SOUNDS += SP0256
SOUNDS += DIGITALKER
SOUNDS += CDP1863
SOUNDS += CDP1864
SOUNDS += ZSG2
#-------------------------------------------------
# this is the list of driver libraries that