mirror of
https://github.com/holub/mame
synced 2025-04-24 17:30:55 +03:00
Added a new sound device: Oki MSM9810. Emulation is not yet perfect.
[out of whatsnew] It sounds ~60% correct, and appears to play the right stuff, but there is still much to do. I'm not respecting the volume command. I'm not taking sample rate into account. I'm not doing anything with stereo yet (though funcube doesn't tickle that functionality). The ADPCM(2?) decoding clearly isn't perfect (I've made a local copy of the oki_adpcm class to mess around with). The way i set the clock in the seta2 driver should show I don't know what I'm doing :). None of the channel flags are being interpreted yet. I haven't hooked up Luca's sigma98 games yet.
This commit is contained in:
parent
297d177dc0
commit
545f57a04c
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -1049,6 +1049,8 @@ src/emu/sound/okim6295.c svneol=native#text/plain
|
||||
src/emu/sound/okim6295.h svneol=native#text/plain
|
||||
src/emu/sound/okim6376.c svneol=native#text/plain
|
||||
src/emu/sound/okim6376.h svneol=native#text/plain
|
||||
src/emu/sound/okim9810.c svneol=native#text/plain
|
||||
src/emu/sound/okim9810.h svneol=native#text/plain
|
||||
src/emu/sound/pokey.c svneol=native#text/plain
|
||||
src/emu/sound/pokey.h svneol=native#text/plain
|
||||
src/emu/sound/pokey.txt svneol=native#text/plain
|
||||
|
478
src/emu/sound/okim9810.c
Normal file
478
src/emu/sound/okim9810.c
Normal file
@ -0,0 +1,478 @@
|
||||
/***************************************************************************
|
||||
|
||||
okim9810.h
|
||||
|
||||
OKI MSM9810 ADCPM(2) sound chip.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "okim9810.h"
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL VARIABLES
|
||||
//**************************************************************************
|
||||
|
||||
// devices
|
||||
const device_type OKIM9810 = okim9810_device_config::static_alloc_device_config;
|
||||
|
||||
|
||||
// default address map
|
||||
static ADDRESS_MAP_START( okim9810, 0, 8 )
|
||||
AM_RANGE(0x000000, 0xffffff) AM_ROM
|
||||
ADDRESS_MAP_END
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// DEVICE CONFIGURATION
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// okim9810_device_config - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
okim9810_device_config::okim9810_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
|
||||
: device_config(mconfig, static_alloc_device_config, "OKI9810", tag, owner, clock),
|
||||
device_config_sound_interface(mconfig, *this),
|
||||
device_config_memory_interface(mconfig, *this),
|
||||
m_space_config("samples", ENDIANNESS_BIG, 8, 24, 0, NULL, *ADDRESS_MAP_NAME(okim9810))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// static_alloc_device_config - allocate a new
|
||||
// configuration object
|
||||
//-------------------------------------------------
|
||||
|
||||
device_config *okim9810_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
|
||||
{
|
||||
return global_alloc(okim9810_device_config(mconfig, tag, owner, clock));
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// alloc_device - allocate a new device object
|
||||
//-------------------------------------------------
|
||||
|
||||
device_t *okim9810_device_config::alloc_device(running_machine &machine) const
|
||||
{
|
||||
return auto_alloc(&machine, okim9810_device(machine, *this));
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// memory_space_config - return a description of
|
||||
// any address spaces owned by this device
|
||||
//-------------------------------------------------
|
||||
|
||||
const address_space_config *okim9810_device_config::memory_space_config(int spacenum) const
|
||||
{
|
||||
return (spacenum == 0) ? &m_space_config : NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// LIVE DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// okim9810_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
okim9810_device::okim9810_device(running_machine &_machine, const okim9810_device_config &config)
|
||||
: device_t(_machine, config),
|
||||
device_sound_interface(_machine, config, *this),
|
||||
device_memory_interface(_machine, config, *this),
|
||||
m_config(config),
|
||||
m_stream(NULL),
|
||||
m_TMP_register(0x00)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void okim9810_device::device_start()
|
||||
{
|
||||
// find our direct access
|
||||
m_direct = &space()->direct();
|
||||
|
||||
// create the stream
|
||||
//int divisor = m_config.m_pin7 ? 132 : 165;
|
||||
m_stream = m_machine.sound().stream_alloc(*this, 0, 1, clock());
|
||||
|
||||
// save state stuff
|
||||
// m_TMP_register
|
||||
// m_voice
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void okim9810_device::device_reset()
|
||||
{
|
||||
m_stream->update();
|
||||
for (int voicenum = 0; voicenum < OKIM9810_VOICES; voicenum++)
|
||||
m_voice[voicenum].m_playing = false;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_post_load - device-specific post-load
|
||||
//-------------------------------------------------
|
||||
|
||||
void okim9810_device::device_post_load()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_clock_changed - called if the clock
|
||||
// changes
|
||||
//-------------------------------------------------
|
||||
|
||||
void okim9810_device::device_clock_changed()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// stream_generate - handle update requests for
|
||||
// our sound stream
|
||||
//-------------------------------------------------
|
||||
|
||||
void okim9810_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
|
||||
{
|
||||
// reset the output stream
|
||||
memset(outputs[0], 0, samples * sizeof(*outputs[0]));
|
||||
|
||||
// iterate over voices and accumulate sample data
|
||||
for (int voicenum = 0; voicenum < OKIM9810_VOICES; voicenum++)
|
||||
m_voice[voicenum].generate_adpcm(*m_direct, outputs[0], samples);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// read_status - read the status register
|
||||
//-------------------------------------------------
|
||||
|
||||
UINT8 okim9810_device::read_status()
|
||||
{
|
||||
UINT8 result = 0x00;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// read - memory interface for read
|
||||
//-------------------------------------------------
|
||||
|
||||
READ8_MEMBER( okim9810_device::read )
|
||||
{
|
||||
return read_status();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// write - memory interface for write
|
||||
//-------------------------------------------------
|
||||
|
||||
// The command is written when the CMD pin is low
|
||||
void okim9810_device::write_command(UINT8 data)
|
||||
{
|
||||
const UINT8 cmd = (data & 0xf8) >> 3;
|
||||
const UINT8 channel = (data & 0x07);
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case 0x00: // START
|
||||
{
|
||||
mame_printf_verbose("START channel mask %02x\n", m_TMP_register);
|
||||
UINT8 channelMask = 0x01;
|
||||
for (int i = 0; i < OKIM9810_VOICES; i++, channelMask <<= 1)
|
||||
{
|
||||
if (channelMask & m_TMP_register)
|
||||
{
|
||||
m_voice[i].m_playing = true;
|
||||
mame_printf_verbose("\t\tPlaying channel %d: type %02x @ %08x for %d samples (looping=%d).\n", i,
|
||||
m_voice[i].m_startFlags,
|
||||
m_voice[i].m_base_offset,
|
||||
m_voice[i].m_count,
|
||||
m_voice[i].m_looping);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x01: // STOP
|
||||
{
|
||||
mame_printf_verbose("STOP channel mask %02x\n", m_TMP_register);
|
||||
UINT8 channelMask = 0x01;
|
||||
for (int i = 0; i < OKIM9810_VOICES; i++, channelMask <<= 1)
|
||||
{
|
||||
if (channelMask & m_TMP_register)
|
||||
{
|
||||
m_voice[i].m_playing = false;
|
||||
mame_printf_verbose("\tChannel %d stopping.\n", i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x02: // LOOP
|
||||
{
|
||||
mame_printf_verbose("LOOP channel mask %02x\n", m_TMP_register);
|
||||
UINT8 channelMask = 0x01;
|
||||
for (int i = 0; i < OKIM9810_VOICES; i++, channelMask <<= 1)
|
||||
{
|
||||
if (channelMask & m_TMP_register)
|
||||
{
|
||||
m_voice[i].m_looping = true;
|
||||
mame_printf_verbose("\tChannel %d looping.\n", i);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_voice[i].m_looping = false;
|
||||
mame_printf_verbose("\tChannel %d done looping.\n", i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x03: // OPT (options)
|
||||
{
|
||||
mame_printf_warning("OPT complex data %02x\n", m_TMP_register);
|
||||
mame_printf_warning("MSM9810: UNIMPLEMENTED COMMAND!\n");
|
||||
break;
|
||||
}
|
||||
case 0x04: // MUON (silence)
|
||||
{
|
||||
mame_printf_warning("MUON channel %d length %02x\n", channel, m_TMP_register);
|
||||
mame_printf_warning("MSM9810: UNIMPLEMENTED COMMAND!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x05: // FADR (phrase address)
|
||||
{
|
||||
const offs_t base = m_TMP_register * 8;
|
||||
|
||||
offs_t startAddr;
|
||||
const UINT8 startFlags = m_direct->read_raw_byte(base + 0);
|
||||
startAddr = m_direct->read_raw_byte(base + 1) << 16;
|
||||
startAddr |= m_direct->read_raw_byte(base + 2) << 8;
|
||||
startAddr |= m_direct->read_raw_byte(base + 3) << 0;
|
||||
|
||||
offs_t endAddr;
|
||||
const UINT8 endFlags = m_direct->read_raw_byte(base + 4);
|
||||
endAddr = m_direct->read_raw_byte(base + 5) << 16;
|
||||
endAddr |= m_direct->read_raw_byte(base + 6) << 8;
|
||||
endAddr |= m_direct->read_raw_byte(base + 7) << 0;
|
||||
|
||||
// Note: flags might be (& 0x30 => voice synthesis algorithm) (& 0x0f => sampling frequency)
|
||||
mame_printf_verbose("FADR channel %d phrase offset %02x => ", channel, m_TMP_register);
|
||||
mame_printf_verbose("\tstartFlags(%02x) startAddr(%06x) endFlags(%02x) endAddr(%06x) bytes(%d)\n", startFlags, startAddr, endFlags, endAddr, endAddr-startAddr);
|
||||
m_voice[channel].m_startFlags = startFlags;
|
||||
m_voice[channel].m_base_offset = startAddr;
|
||||
m_voice[channel].m_endFlags = endFlags;
|
||||
m_voice[channel].m_sample = 0;
|
||||
// TODO: Sample count (m_count) changes based on decoding mode
|
||||
m_voice[channel].m_count = 2 * ((endAddr-startAddr) + 1); // TODO: Explain the +1
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x06: // DADR (direct address playback)
|
||||
{
|
||||
mame_printf_warning("DADR channel %d complex data %02x\n", channel, m_TMP_register);
|
||||
mame_printf_warning("MSM9810: UNIMPLEMENTED COMMAND!\n");
|
||||
break;
|
||||
}
|
||||
case 0x07: // CVOL (channel volume)
|
||||
{
|
||||
mame_printf_verbose("CVOL channel %d volume level %02x\n", channel, m_TMP_register);
|
||||
mame_printf_verbose("\tChannel %d -> volume %d.\n", channel, m_TMP_register);
|
||||
|
||||
// TODO: Use the proper volume table p37
|
||||
m_voice[channel].m_volume = m_TMP_register;
|
||||
break;
|
||||
}
|
||||
case 0x08: // PAN
|
||||
{
|
||||
mame_printf_warning("PAN channel %d volume level %02x\n", channel, m_TMP_register);
|
||||
mame_printf_warning("MSM9810: UNIMPLEMENTED COMMAND!\n");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
mame_printf_warning("MSM9810: UNKNOWN COMMAND!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WRITE8_MEMBER( okim9810_device::write )
|
||||
{
|
||||
write_command(data);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// writeTMP - memory interface for writing the TMP register
|
||||
//-----------------------------------------------------------
|
||||
|
||||
// TMP is written when the CMD pin is high
|
||||
void okim9810_device::write_TMP_register(UINT8 data)
|
||||
{
|
||||
m_TMP_register = data;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER( okim9810_device::write_TMP_register )
|
||||
{
|
||||
write_TMP_register(data);
|
||||
}
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// OKIM VOICE
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// okim_voice - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
okim9810_device::okim_voice::okim_voice()
|
||||
: m_playing(false),
|
||||
m_looping(false),
|
||||
m_startFlags(0),
|
||||
m_endFlags(0),
|
||||
m_base_offset(0),
|
||||
m_sample(0),
|
||||
m_count(0),
|
||||
m_volume(0)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// generate_adpcm - generate ADPCM samples and
|
||||
// add them to an output stream
|
||||
//-------------------------------------------------
|
||||
|
||||
void okim9810_device::okim_voice::generate_adpcm(direct_read_data &direct, stream_sample_t *buffer, int samples)
|
||||
{
|
||||
// skip if not active
|
||||
if (!m_playing)
|
||||
return;
|
||||
|
||||
// loop while we still have samples to generate
|
||||
while (samples-- != 0)
|
||||
{
|
||||
// fetch the next sample byte
|
||||
int nibble = direct.read_raw_byte(m_base_offset + m_sample / 2) >> (((m_sample & 1) << 2) ^ 4);
|
||||
|
||||
// output to the buffer, scaling by the volume
|
||||
// signal in range -2048..2047, volume in range 2..32 => signal * volume / 2 in range -32768..32767
|
||||
*buffer++ += m_adpcm.clock(nibble); //TODO * m_volume / 2;
|
||||
|
||||
// next!
|
||||
if (++m_sample >= m_count)
|
||||
{
|
||||
if (!m_looping)
|
||||
m_playing = false;
|
||||
else
|
||||
m_sample = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// ADPCM STATE HELPER
|
||||
//**************************************************************************
|
||||
|
||||
// ADPCM state and tables
|
||||
bool adpcm_stateCopy::s_tables_computed = false;
|
||||
const INT8 adpcm_stateCopy::s_index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
|
||||
int adpcm_stateCopy::s_diff_lookup[49*16];
|
||||
|
||||
//-------------------------------------------------
|
||||
// reset - reset the ADPCM state
|
||||
//-------------------------------------------------
|
||||
|
||||
void adpcm_stateCopy::reset()
|
||||
{
|
||||
// reset the signal/step
|
||||
m_signal = -2;
|
||||
m_step = 0;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_clock_changed - called if the clock
|
||||
// changes
|
||||
//-------------------------------------------------
|
||||
|
||||
INT16 adpcm_stateCopy::clock(UINT8 nibble)
|
||||
{
|
||||
// update the signal
|
||||
m_signal += s_diff_lookup[m_step * 16 + (nibble & 15)];
|
||||
|
||||
// clamp to the maximum
|
||||
if (m_signal > 2047)
|
||||
m_signal = 2047;
|
||||
else if (m_signal < -2048)
|
||||
m_signal = -2048;
|
||||
|
||||
// adjust the step size and clamp
|
||||
m_step += s_index_shift[nibble & 7];
|
||||
if (m_step > 48)
|
||||
m_step = 48;
|
||||
else if (m_step < 0)
|
||||
m_step = 0;
|
||||
|
||||
// return the signal
|
||||
return m_signal;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// compute_tables - precompute tables for faster
|
||||
// sound generation
|
||||
//-------------------------------------------------
|
||||
|
||||
void adpcm_stateCopy::compute_tables()
|
||||
{
|
||||
// skip if we already did it
|
||||
if (s_tables_computed)
|
||||
return;
|
||||
s_tables_computed = true;
|
||||
|
||||
// nibble to bit map
|
||||
static const INT8 nbl2bit[16][4] =
|
||||
{
|
||||
{ 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1},
|
||||
{ 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1},
|
||||
{-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1},
|
||||
{-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1}
|
||||
};
|
||||
|
||||
// loop over all possible steps
|
||||
for (int step = 0; step <= 48; step++)
|
||||
{
|
||||
// compute the step value
|
||||
int stepval = floor(16.0 * pow(11.0 / 10.0, (double)step));
|
||||
|
||||
// loop over all nibbles and compute the difference
|
||||
for (int nib = 0; nib < 16; nib++)
|
||||
{
|
||||
s_diff_lookup[step*16 + nib] = nbl2bit[nib][0] *
|
||||
(stepval * nbl2bit[nib][1] +
|
||||
stepval/2 * nbl2bit[nib][2] +
|
||||
stepval/4 * nbl2bit[nib][3] +
|
||||
stepval/8);
|
||||
}
|
||||
}
|
||||
}
|
164
src/emu/sound/okim9810.h
Normal file
164
src/emu/sound/okim9810.h
Normal file
@ -0,0 +1,164 @@
|
||||
/***************************************************************************
|
||||
|
||||
okim9810.h
|
||||
|
||||
OKI MSM9810 ADCPM(2) sound chip.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __OKIM9810_H__
|
||||
#define __OKIM9810_H__
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// CONSTANTS
|
||||
//**************************************************************************
|
||||
|
||||
enum
|
||||
{
|
||||
OKIM9810_SERIAL_PIN_LOW = 0,
|
||||
OKIM9810_SERIAL_PIN_HIGH = 1,
|
||||
// etc
|
||||
};
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// INTERFACE CONFIGURATION MACROS
|
||||
//**************************************************************************
|
||||
|
||||
#define MCFG_OKIM9810_ADD(_tag, _clock) \
|
||||
MCFG_DEVICE_ADD(_tag, OKIM9810, _clock)
|
||||
|
||||
#define MCFG_OKIM9810_REPLACE(_tag, _clock) \
|
||||
MCFG_DEVICE_REPLACE(_tag, OKIM9810, _clock)
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// ======================> adpcm_stateCopy
|
||||
|
||||
// Internal ADPCM state, used by external ADPCM generators with compatible specs to the OKIM 6295.
|
||||
class adpcm_stateCopy
|
||||
{
|
||||
public:
|
||||
adpcm_stateCopy() { compute_tables(); reset(); }
|
||||
|
||||
void reset();
|
||||
INT16 clock(UINT8 nibble);
|
||||
|
||||
INT32 m_signal;
|
||||
INT32 m_step;
|
||||
|
||||
private:
|
||||
static const INT8 s_index_shift[8];
|
||||
static int s_diff_lookup[49*16];
|
||||
|
||||
static void compute_tables();
|
||||
static bool s_tables_computed;
|
||||
};
|
||||
|
||||
|
||||
// ======================> okim9810_device_config
|
||||
|
||||
class okim9810_device_config : public device_config,
|
||||
public device_config_sound_interface,
|
||||
public device_config_memory_interface
|
||||
{
|
||||
friend class okim9810_device;
|
||||
|
||||
// construction/destruction
|
||||
okim9810_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
|
||||
|
||||
public:
|
||||
// allocators
|
||||
static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
|
||||
virtual device_t *alloc_device(running_machine &machine) const;
|
||||
|
||||
protected:
|
||||
// device_config overrides
|
||||
virtual const address_space_config *memory_space_config(int spacenum = 0) const;
|
||||
|
||||
// internal state
|
||||
const address_space_config m_space_config;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ======================> okim9810_device
|
||||
|
||||
class okim9810_device : public device_t,
|
||||
public device_sound_interface,
|
||||
public device_memory_interface
|
||||
{
|
||||
friend class okim9810_device_config;
|
||||
|
||||
// construction/destruction
|
||||
okim9810_device(running_machine &_machine, const okim9810_device_config &config);
|
||||
|
||||
public:
|
||||
|
||||
UINT8 read_status();
|
||||
void write_TMP_register(UINT8 command);
|
||||
void write_command(UINT8 command);
|
||||
|
||||
DECLARE_READ8_MEMBER( read );
|
||||
DECLARE_WRITE8_MEMBER( write );
|
||||
DECLARE_WRITE8_MEMBER( write_TMP_register );
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
virtual void device_post_load();
|
||||
virtual void device_clock_changed();
|
||||
|
||||
// sound interface overrides
|
||||
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
|
||||
|
||||
// a single voice
|
||||
class okim_voice
|
||||
{
|
||||
public:
|
||||
okim_voice();
|
||||
void generate_adpcm(direct_read_data &direct, stream_sample_t *buffer, int samples);
|
||||
|
||||
adpcm_stateCopy m_adpcm; // current ADPCM state
|
||||
bool m_playing;
|
||||
bool m_looping;
|
||||
UINT8 m_startFlags;
|
||||
UINT8 m_endFlags;
|
||||
offs_t m_base_offset; // pointer to the base memory location
|
||||
UINT32 m_sample; // current sample number
|
||||
UINT32 m_count; // total bytes to play
|
||||
|
||||
INT8 m_volume; // output volume
|
||||
// TODO: m_volume_left; // stereo volume
|
||||
// TODO: m_volume_right; // stereo volume
|
||||
};
|
||||
|
||||
|
||||
// internal state
|
||||
const okim9810_device_config &m_config;
|
||||
|
||||
sound_stream* m_stream;
|
||||
direct_read_data* m_direct;
|
||||
|
||||
UINT8 m_TMP_register;
|
||||
|
||||
static const int OKIM9810_VOICES = 8;
|
||||
okim_voice m_voice[OKIM9810_VOICES];
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
extern const device_type OKIM9810;
|
||||
|
||||
|
||||
|
||||
#endif // __OKIM9810_H__
|
@ -376,6 +376,10 @@ ifneq ($(filter OKIM6258,$(SOUNDS)),)
|
||||
SOUNDOBJS += $(SOUNDOBJ)/okim6258.o
|
||||
endif
|
||||
|
||||
ifneq ($(filter OKIM9810,$(SOUNDS)),)
|
||||
SOUNDOBJS += $(SOUNDOBJ)/okim9810.o
|
||||
endif
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------
|
||||
|
@ -535,6 +535,7 @@ The same H8/3007 code "FC21 IOPR-0" at U49 is used for FUNCUBE 2,3,4 & 5
|
||||
#include "cpu/h83002/h8.h"
|
||||
#include "machine/eeprom.h"
|
||||
#include "sound/x1_010.h"
|
||||
#include "sound/okim9810.h"
|
||||
#include "includes/seta2.h"
|
||||
#include "machine/nvram.h"
|
||||
|
||||
@ -959,6 +960,20 @@ static READ32_HANDLER( funcube_debug_r )
|
||||
return ret;
|
||||
}
|
||||
|
||||
static WRITE32_DEVICE_HANDLER( oki_write )
|
||||
{
|
||||
if (ACCESSING_BITS_0_7)
|
||||
{
|
||||
const UINT8 tmp = (data & 0x000000ff);
|
||||
downcast<okim9810_device *>(device)->write_TMP_register(tmp);
|
||||
}
|
||||
else if (ACCESSING_BITS_16_23)
|
||||
{
|
||||
const UINT8 cmd = (data & 0x00ff0000) >> 16;
|
||||
downcast<okim9810_device *>(device)->write_command(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ADDRESS_MAP_START( funcube_map, ADDRESS_SPACE_PROGRAM, 32 )
|
||||
AM_RANGE( 0x00000000, 0x0007ffff ) AM_ROM
|
||||
@ -967,7 +982,7 @@ static ADDRESS_MAP_START( funcube_map, ADDRESS_SPACE_PROGRAM, 32 )
|
||||
AM_RANGE( 0x00500000, 0x00500003 ) AM_READ( funcube_debug_r )
|
||||
AM_RANGE( 0x00500004, 0x00500007 ) AM_READ( watchdog_reset32_r ) AM_WRITENOP
|
||||
|
||||
AM_RANGE( 0x00600000, 0x00600003 ) AM_WRITENOP // sound chip
|
||||
AM_RANGE( 0x00600000, 0x00600003 ) AM_DEVWRITE("oki", oki_write)
|
||||
|
||||
AM_RANGE( 0x00800000, 0x0083ffff ) AM_READWRITE( spriteram32_dword_r, spriteram32_dword_w ) AM_BASE_SIZE_MEMBER(seta2_state, spriteram, spriteram_size)
|
||||
AM_RANGE( 0x00840000, 0x0084ffff ) AM_READWRITE( paletteram32_dword_r, paletteram32_dword_w ) AM_BASE_GENERIC(paletteram)
|
||||
@ -2494,9 +2509,11 @@ static MACHINE_CONFIG_START( funcube, seta2_state )
|
||||
MCFG_VIDEO_EOF(seta2)
|
||||
|
||||
/* sound hardware */
|
||||
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
|
||||
|
||||
// MSM9810B
|
||||
|
||||
MCFG_OKIM9810_ADD("oki", XTAL_14_7456MHz/10/10/10)
|
||||
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.80)
|
||||
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.80)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
|
||||
@ -2804,8 +2821,8 @@ ROM_START( funcube2 )
|
||||
ROM_LOAD32_WORD( "fc21_obj-0.u43", 0x000000, 0x400000, CRC(08cfe6d9) SHA1(d10f362dcde01f7a9855d8f76af3084b5dd1573a) )
|
||||
ROM_LOAD32_WORD( "fc21_obj-1.u42", 0x000002, 0x400000, CRC(4c1fbc20) SHA1(ff83691c19ce3600b31c494eaec26d2ac79e0028) )
|
||||
|
||||
ROM_REGION( 0x400000, "samples", 0 )
|
||||
ROM_LOAD( "fc21_voi0.u47", 0x00000, 0x400000, CRC(25b5fc3f) SHA1(18b16a14e9ee62f3fea382e9d3fdcd43bdb165f5) )
|
||||
ROM_REGION( 0x1000000, "oki", 0 )
|
||||
ROM_LOAD( "fc21_voi0.u47", 0x000000, 0x400000, CRC(25b5fc3f) SHA1(18b16a14e9ee62f3fea382e9d3fdcd43bdb165f5) )
|
||||
ROM_END
|
||||
|
||||
ROM_START( funcube4 )
|
||||
@ -2822,8 +2839,8 @@ ROM_START( funcube4 )
|
||||
ROM_LOAD32_WORD( "fc41_obj-0.u43", 0x000000, 0x400000, CRC(9ff029d5) SHA1(e057f4929aa745ecaf9d4ff7e39974c82e440146) )
|
||||
ROM_LOAD32_WORD( "fc41_obj-1.u42", 0x000002, 0x400000, CRC(5ab7b087) SHA1(c600158b2358cdf947357170044dda2deacd4f37) )
|
||||
|
||||
ROM_REGION( 0x400000, "samples", 0 )
|
||||
ROM_LOAD( "fc41_snd0.u47", 0x00000, 0x400000, CRC(48337257) SHA1(d1755024b824100070b489f48f6ae921765329e8) )
|
||||
ROM_REGION( 0x1000000, "oki", 0 )
|
||||
ROM_LOAD( "fc41_snd0.u47", 0x000000, 0x400000, CRC(48337257) SHA1(d1755024b824100070b489f48f6ae921765329e8) )
|
||||
ROM_END
|
||||
|
||||
static DRIVER_INIT( funcube2 )
|
||||
@ -2841,8 +2858,15 @@ static DRIVER_INIT( funcube2 )
|
||||
main_cpu[0xa8c/4] = 0x4e7141f9;
|
||||
|
||||
// Sub CPU
|
||||
|
||||
sub_cpu[0x4d4/2] = 0x5470; // rte -> rts
|
||||
|
||||
// Audio
|
||||
// The first half of the rom appears to be a dupe of the second half with 0xffs destructively interleaved
|
||||
UINT8* oki = (UINT8*) machine->region("oki")->base();
|
||||
for (int i = 0; i < 0x200000; i++)
|
||||
{
|
||||
oki[i] = oki[i+0x200000];
|
||||
}
|
||||
}
|
||||
|
||||
// Note: same as funcube2
|
||||
@ -2861,8 +2885,15 @@ static DRIVER_INIT( funcube4 )
|
||||
main_cpu[0xa8c/4] = 0x4e7141f9;
|
||||
|
||||
// Sub CPU
|
||||
|
||||
sub_cpu[0x4d4/2] = 0x5470; // rte -> rts
|
||||
|
||||
// Audio
|
||||
// The first half of the rom appears to be a dupe of the second half with 0xffs destructively interleaved
|
||||
UINT8* oki = (UINT8*) machine->region("oki")->base();
|
||||
for (int i = 0; i < 0x200000; i++)
|
||||
{
|
||||
oki[i] = oki[i+0x200000];
|
||||
}
|
||||
}
|
||||
|
||||
GAME( 1994, gundamex, 0, gundamex, gundamex, 0, ROT0, "Banpresto", "Mobile Suit Gundam EX Revue", 0 )
|
||||
|
@ -177,6 +177,7 @@ SOUNDS += MSM5232
|
||||
SOUNDS += OKIM6258
|
||||
SOUNDS += OKIM6295
|
||||
SOUNDS += OKIM6376
|
||||
SOUNDS += OKIM9810
|
||||
SOUNDS += UPD7759
|
||||
SOUNDS += HC55516
|
||||
SOUNDS += K005289
|
||||
|
Loading…
Reference in New Issue
Block a user