sms.cpp: fix Out Run sound in FM mode [Enik Land]

This commit is contained in:
MetalliC 2016-10-10 23:56:29 +03:00
parent 980588badf
commit 3d850be071
4 changed files with 64 additions and 23 deletions

View File

@ -11,13 +11,31 @@ Release data from the Sega Retro project:
Notes:
This emulation is based on Charles MacDonald's analysis of Enri's schematics
of the FM unit hardware.
The FM Unit add-on was released for the Mark III, so compatible games were
released only for that console and the Japanese SMS, that has the FM chip
built-in. The games play FM sound only when detect the FM hardware. The normal
PSG sound is replaced, except when sampled voices, not supported by the FM
chip, are played. Some games released for western SMS versions also contain FM
code, that is played on a Mark III / SMSJ when connected through a cartridge
adapter.
The IO address map (read/write ports) is based on Charles MacDonald's analysis
of Enri's schematics of the FM unit hardware.
Any software that access controllers through IO ports $C0/$C1 instead $DC/$DD
(the game Fushigi no Oshiro Pit Pot is a known example) has control problems
when the FM Sound Unit is attached (real hardware behavior).
TODO:
- Confirm the assumption that PSG and FM sound are not mixed by the FM unit
and there is only FM sound when the unit is enabled. Two evidences that were
observed: every time a game with FM sound plays sampled voices through PSG,
the game disables/enables the FM chip before/after playing the PSG sound, and
a user reported, on the topic of the SMSPower Forums where the PSG/FM mixing
control of the SMSJ was discovered, that the hack that adds FM sound to Sonic
SMS version is not playing PSG sound on his Mark III with the FM unit.
**********************************************************************/
#include "fm_unit.h"
@ -33,6 +51,8 @@ const device_type SEGA_FM_UNIT = &device_creator<sega_fm_unit_device>;
static MACHINE_CONFIG_FRAGMENT( fm_config )
MCFG_SOUND_ADD("ym2413", YM2413, XTAL_10_738635MHz/3)
// if this output gain is changed, the gain set when unmute the output need
// to be changed too, probably along the gain set for SMSJ/SMSKRFM drivers.
MCFG_SOUND_ROUTE(ALL_OUTPUTS, ":mono", 1.00)
MACHINE_CONFIG_END
@ -56,6 +76,7 @@ sega_fm_unit_device::sega_fm_unit_device(const machine_config &mconfig, const ch
device_t(mconfig, SEGA_FM_UNIT, "Sega FM Sound Unit", tag, owner, clock, "sega_fm_unit", __FILE__),
device_sg1000_expansion_slot_interface(mconfig, *this),
m_ym(*this, "ym2413"),
m_psg(*this, ":segapsg"),
m_audio_control(0)
{
}
@ -78,6 +99,8 @@ void sega_fm_unit_device::device_start()
READ8_MEMBER(sega_fm_unit_device::peripheral_r)
{
// the value previously written to the control port is returned on all
// active read offsets.
if (offset <= 3)
{
return m_audio_control & 0x01;
@ -95,20 +118,28 @@ WRITE8_MEMBER(sega_fm_unit_device::peripheral_w)
switch (offset)
{
case 0: // register port
if (m_audio_control == 0x01)
{
m_ym->write(space, 0, data & 0x3f);
}
m_ym->write(space, 0, data & 0x3f);
break;
case 1: // data port
if (m_audio_control == 0x01)
{
m_ym->write(space, 1, data);
}
m_ym->write(space, 1, data);
break;
case 2: // control port
case 3: // mirror
m_audio_control = data & 0x01;
if (m_audio_control == 0x01)
{
m_ym->set_output_gain(0, 1.0);
// assume the PSG output is muted when FM is active.
// Out Run need this. Needs confirmation (see TODO).
if (m_psg.found())
m_psg->set_output_gain(0, 0.0);
}
else
{
m_ym->set_output_gain(0, 0.0);
if (m_psg.found())
m_psg->set_output_gain(0, 1.0);
}
break;
default:
break;

View File

@ -14,6 +14,7 @@
#include "emu.h"
#include "sound/ym2413.h"
#include "sound/sn76496.h"
#include "sg1000exp.h"
@ -44,6 +45,7 @@ protected:
private:
required_device<ym2413_device> m_ym;
optional_device<segapsg_device> m_psg;
UINT8 m_audio_control;
};

View File

@ -890,6 +890,8 @@ static MACHINE_CONFIG_DERIVED( smsj, sms1_kr )
MCFG_CPU_IO_MAP(smsj_io)
MCFG_SOUND_ADD("ym2413", YM2413, XTAL_10_738635MHz/3)
// if this output gain is changed, the gain set when unmute the output need
// to be changed too, probably along the gain set for the Mark III FM Unit.
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
MACHINE_CONFIG_END

View File

@ -458,6 +458,22 @@ READ8_MEMBER(sms_state::sms_input_port_dd_r)
WRITE8_MEMBER(sms_state::smsj_audio_control_w)
{
m_smsj_audio_control = data & 0x03;
/* Mute settings:
0,0 : PSG only (power-on default)
0,1 : FM only
1,0 : Both PSG and FM disabled
1,1 : Both PSG and FM enabled
*/
if (m_smsj_audio_control == 0x00 || m_smsj_audio_control == 0x03)
m_psg_sms->set_output_gain(0, 1.0);
else
m_psg_sms->set_output_gain(0, 0.0);
if (m_smsj_audio_control == 0x01 || m_smsj_audio_control == 0x03)
m_ym->set_output_gain(0, 1.0);
else
m_ym->set_output_gain(0, 0.0);
}
@ -492,29 +508,19 @@ READ8_MEMBER(sms_state::smsj_audio_control_r)
WRITE8_MEMBER(sms_state::smsj_ym2413_register_port_w)
{
if (m_smsj_audio_control == 0x01 || m_smsj_audio_control == 0x03)
m_ym->write(space, 0, data & 0x3f);
m_ym->write(space, 0, data & 0x3f);
}
WRITE8_MEMBER(sms_state::smsj_ym2413_data_port_w)
{
if (m_smsj_audio_control == 0x01 || m_smsj_audio_control == 0x03)
{
//logerror("data_port_w %x %x\n", offset, data);
m_ym->write(space, 1, data);
}
//logerror("data_port_w %x %x\n", offset, data);
m_ym->write(space, 1, data);
}
WRITE8_MEMBER(sms_state::sms_psg_w)
{
if (m_is_smsj)
{
if (m_smsj_audio_control != 0x00 && m_smsj_audio_control != 0x03)
return;
}
m_psg_sms->write(space, offset, data, mem_mask);
}