mirror of
https://github.com/holub/mame
synced 2025-05-29 17:13:05 +03:00
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:
parent
1f76758746
commit
49e9851b24
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -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
|
||||
|
@ -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
251
src/emu/sound/zsg2.c
Normal 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
22
src/emu/sound/zsg2.h
Normal 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__ */
|
@ -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
|
||||
|
@ -220,7 +220,7 @@ SOUNDS += SP0256
|
||||
SOUNDS += DIGITALKER
|
||||
SOUNDS += CDP1863
|
||||
SOUNDS += CDP1864
|
||||
|
||||
SOUNDS += ZSG2
|
||||
|
||||
#-------------------------------------------------
|
||||
# this is the list of driver libraries that
|
||||
|
Loading…
Reference in New Issue
Block a user