vgmplay: WonderSwan sound is working now. Sound is muted when songs end. [smf]

This commit is contained in:
smf- 2018-08-09 20:30:36 +01:00
parent ba43e8da6f
commit 3b48aed0bf
6 changed files with 135 additions and 88 deletions

View File

@ -32,6 +32,7 @@ DEFINE_DEVICE_TYPE(WSWAN_SND, wswan_sound_device, "wswan_sound", "WonderSwan Cus
wswan_sound_device::wswan_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, WSWAN_SND, tag, owner, clock),
device_sound_interface(mconfig, *this),
device_rom_interface(mconfig, *this, 14),
m_channel(nullptr),
m_sweep_step(0),
m_sweep_time(0),
@ -39,12 +40,12 @@ wswan_sound_device::wswan_sound_device(const machine_config &mconfig, const char
m_noise_type(0),
m_noise_reset(0),
m_noise_enable(0),
m_noise_output(0),
m_sample_address(0),
m_audio2_voice(0),
m_audio3_sweep(0),
m_audio4_noise(0),
m_mono(0),
m_voice_data(0),
m_output_volume(0),
m_external_stereo(0),
m_external_speaker(0),
@ -53,6 +54,7 @@ wswan_sound_device::wswan_sound_device(const machine_config &mconfig, const char
{
}
constexpr int clk_div = 64;
//-------------------------------------------------
// device_start - device-specific startup
@ -60,7 +62,7 @@ wswan_sound_device::wswan_sound_device(const machine_config &mconfig, const char
void wswan_sound_device::device_start()
{
m_channel = stream_alloc(0, 2, machine().sample_rate());
m_channel = stream_alloc(0, 2, clock() / clk_div);
save_item(NAME(m_sweep_step));
save_item(NAME(m_sweep_time));
@ -73,7 +75,6 @@ void wswan_sound_device::device_start()
save_item(NAME(m_audio3_sweep));
save_item(NAME(m_audio4_noise));
save_item(NAME(m_mono));
save_item(NAME(m_voice_data));
save_item(NAME(m_output_volume));
save_item(NAME(m_external_stereo));
save_item(NAME(m_external_speaker));
@ -86,6 +87,7 @@ void wswan_sound_device::device_start()
save_item(NAME(m_audio1.vol_left));
save_item(NAME(m_audio1.vol_right));
save_item(NAME(m_audio1.on));
save_item(NAME(m_audio1.offset));
save_item(NAME(m_audio1.signal));
save_item(NAME(m_audio2.freq));
@ -94,6 +96,7 @@ void wswan_sound_device::device_start()
save_item(NAME(m_audio2.vol_left));
save_item(NAME(m_audio2.vol_right));
save_item(NAME(m_audio2.on));
save_item(NAME(m_audio2.offset));
save_item(NAME(m_audio2.signal));
save_item(NAME(m_audio3.freq));
@ -102,6 +105,7 @@ void wswan_sound_device::device_start()
save_item(NAME(m_audio3.vol_left));
save_item(NAME(m_audio3.vol_right));
save_item(NAME(m_audio3.on));
save_item(NAME(m_audio3.offset));
save_item(NAME(m_audio3.signal));
save_item(NAME(m_audio4.freq));
@ -110,9 +114,19 @@ void wswan_sound_device::device_start()
save_item(NAME(m_audio4.vol_left));
save_item(NAME(m_audio4.vol_right));
save_item(NAME(m_audio4.on));
save_item(NAME(m_audio4.offset));
save_item(NAME(m_audio4.signal));
}
void wswan_sound_device::device_clock_changed()
{
m_channel->set_sample_rate(clock() / clk_div);
}
void wswan_sound_device::rom_bank_updated()
{
m_channel->update();
}
//-------------------------------------------------
// device_reset
@ -121,19 +135,33 @@ void wswan_sound_device::device_start()
void wswan_sound_device::device_reset()
{
m_audio1.on = 0;
m_audio1.signal = 16;
m_audio1.signal = 0;
m_audio1.offset = 0;
m_audio1.pos = 0;
m_audio2.on = 0;
m_audio2.signal = 16;
m_audio2.signal = 0;
m_audio2.offset = 0;
m_audio2.pos = 0;
m_audio3.on = 0;
m_audio3.signal = 16;
m_audio3.signal = 0;
m_audio3.offset = 0;
m_audio3.pos = 0;
m_audio4.on = 0;
m_audio4.signal = 16;
m_audio4.signal = 0;
m_audio4.offset = 0;
m_audio4.pos = 0;
m_noise_output = 0;
}
int wswan_sound_device::fetch_sample(int channel, int offset)
{
uint8_t b = read_byte(m_sample_address + ((channel & 3) << 4) + ((offset & 0x1f) >> 1));
if (offset & 1)
return b >> 4;
else
return b & 0xf;
}
//-------------------------------------------------
// sound_stream_update - handle a stream update
@ -150,11 +178,11 @@ void wswan_sound_device::sound_stream_update(sound_stream &stream, stream_sample
if ( m_audio1.on )
{
sample = m_audio1.signal;
m_audio1.pos++;
if ( m_audio1.pos >= m_audio1.period / 2 )
m_audio1.pos += clk_div;
if (m_audio1.pos >= m_audio1.period)
{
m_audio1.pos = 0;
m_audio1.signal = -m_audio1.signal;
m_audio1.pos -= m_audio1.period;
m_audio1.signal = fetch_sample(0, m_audio1.offset++);
}
left += m_audio1.vol_left * sample;
right += m_audio1.vol_right * sample;
@ -164,17 +192,18 @@ void wswan_sound_device::sound_stream_update(sound_stream &stream, stream_sample
{
if ( m_audio2_voice )
{
left += (m_voice_data - 128)*(m_master_volume & 0x0f);
right += (m_voice_data - 128)*(m_master_volume & 0x0f);
uint8_t voice_data = m_audio2.vol_left << 4 | m_audio2.vol_right;
left += voice_data * (m_master_volume & 0x0f);
right += voice_data * (m_master_volume & 0x0f);
}
else
{
sample = m_audio2.signal;
m_audio2.pos++;
if ( m_audio2.pos >= m_audio2.period / 2 )
m_audio2.pos += clk_div;
if (m_audio2.pos >= m_audio2.period)
{
m_audio2.pos = 0;
m_audio2.signal = -m_audio2.signal;
m_audio2.pos -= m_audio2.period;
m_audio2.signal = fetch_sample(1, m_audio2.offset++);
}
left += m_audio2.vol_left * sample;
right += m_audio2.vol_right * sample;
@ -184,20 +213,21 @@ void wswan_sound_device::sound_stream_update(sound_stream &stream, stream_sample
if ( m_audio3.on )
{
sample = m_audio3.signal;
m_audio3.pos++;
if ( m_audio3.pos >= m_audio3.period / 2 )
m_audio3.pos += clk_div;
if (m_audio3.pos >= m_audio3.period)
{
m_audio3.pos = 0;
m_audio3.signal = -m_audio3.signal;
m_audio3.pos -= m_audio3.period;
m_audio3.signal = fetch_sample(2, m_audio3.offset++);
}
if ( m_audio3_sweep && m_sweep_time )
{
m_sweep_count++;
m_sweep_count += clk_div;
if ( m_sweep_count >= m_sweep_time )
{
m_sweep_count = 0;
m_sweep_count -= m_sweep_time;
m_audio3.freq += m_sweep_step;
m_audio3.period = machine().sample_rate() / (3072000 / ((2048 - (m_audio3.freq & 0x7ff)) << 5));
m_audio3.freq &= 0x7ff;
m_audio3.period = 2048 - m_audio3.freq;
}
}
left += m_audio3.vol_left * sample;
@ -207,39 +237,29 @@ void wswan_sound_device::sound_stream_update(sound_stream &stream, stream_sample
if ( m_audio4.on )
{
sample = m_audio4.signal;
m_audio4.pos++;
if ( m_audio4.pos >= m_audio4.period / 2 )
m_audio4.pos += clk_div;
if (m_audio4.pos >= m_audio4.period)
{
m_audio4.signal = -m_audio4.signal;
m_audio4.pos = 0;
if (m_audio4_noise)
m_audio4.signal = m_noise_output ? 0xf : 0;
else
m_audio4.signal = fetch_sample(3, m_audio4.offset++);
m_audio4.pos -= m_audio4.period;
if (m_noise_reset)
{
m_noise_reset = 0;
m_noise_shift = 0;
m_noise_output = 0;
}
if (m_noise_enable)
{
uint16_t new_bit = 0;
static int shift_bit[] = { 14, 10, 13, 4, 8, 6, 9, 11 };
if (m_noise_type == 0)
{
new_bit = (m_noise_shift ^ (m_noise_shift >> 5) ^ (m_noise_shift >> 8)) & 1;
}
else
{
static int shift_bit[] = { 0, 10, 13, 4, 8, 6, 9, 11 };
new_bit = (1 ^ (m_noise_shift >> 7) ^ (m_noise_shift >> shift_bit[m_noise_type])) & 1;
}
m_noise_shift = (m_noise_shift << 1) | new_bit;
if (m_audio4_noise)
{
m_audio4.signal = (m_noise_shift & 0x8000) ? 16 : -16;
}
m_noise_shift &= 0x7fff;
if (m_noise_shift == 0x7fff)
{
m_noise_shift = (m_noise_type == 0) ? 0x80 : 0;
}
m_noise_output = (1 ^ (m_noise_shift >> 7) ^ (m_noise_shift >> shift_bit[m_noise_type])) & 1;
m_noise_shift = m_noise_shift << 1 | m_noise_output;
}
}
left += m_audio4.vol_left * sample;
@ -259,7 +279,7 @@ void wswan_sound_device::wswan_ch_set_freq( CHAN *ch, uint16_t freq )
{
freq &= 0x7ff; // docs say freq is 11bits and a few games (Morita Shougi, World Stadium + others) write 0x800 causing a divide by 0 crash
ch->freq = freq;
ch->period = machine().sample_rate() / (3072000 / ((2048 - freq) << 5));
ch->period = 2048 - freq;
}
WRITE8_MEMBER( wswan_sound_device::port_w )
@ -306,7 +326,6 @@ WRITE8_MEMBER( wswan_sound_device::port_w )
break;
case 0x89: /* Audio 2 volume */
m_voice_data = data;
m_audio2.vol_left = ( data & 0xF0 ) >> 4;
m_audio2.vol_right = data & 0x0F;
break;
@ -326,17 +345,13 @@ WRITE8_MEMBER( wswan_sound_device::port_w )
break;
case 0x8D: /* Sweep time */
m_sweep_time = machine().sample_rate() / ( 3072000 / ( 8192 * (data + 1) ) );
m_sweep_time = 8192 * (data + 1);
break;
case 0x8E: /* Noise control */
m_noise_type = data & 0x07;
m_noise_reset = ( data & 0x08 ) >> 3;
m_noise_enable = ( data & 0x10 ) >> 4;
if (m_noise_reset)
{
m_noise_shift = (m_noise_type == 0) ? 0x80 : 0;
}
break;
case 0x8F: /* Sample location */

View File

@ -19,7 +19,8 @@
// ======================> wswan_sound_device
class wswan_sound_device : public device_t,
public device_sound_interface
public device_sound_interface,
public device_rom_interface
{
public:
wswan_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@ -36,26 +37,32 @@ protected:
vol_left(0),
vol_right(0),
on(0),
offset(0),
signal(0) { }
uint16_t freq; /* frequency */
uint32_t period; /* period */
uint32_t pos; /* position */
uint16_t period; /* period */
int32_t pos; /* position */
uint8_t vol_left; /* volume left */
uint8_t vol_right; /* volume right */
uint8_t on; /* on/off */
int8_t signal; /* signal */
uint8_t offset; /* sample offset */
uint8_t signal; /* signal */
};
// device-level overrides
virtual void device_start() override;
virtual void device_clock_changed() override;
virtual void device_reset() override;
virtual void rom_bank_updated() override;
// sound stream update overrides
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
private:
void wswan_ch_set_freq( CHAN *ch, uint16_t freq );
int fetch_sample(int channel, int offset);
sound_stream *m_channel;
CHAN m_audio1; /* Audio channel 1 */
@ -64,16 +71,16 @@ private:
CHAN m_audio4; /* Audio channel 4 */
int8_t m_sweep_step; /* Sweep step */
uint32_t m_sweep_time; /* Sweep time */
uint32_t m_sweep_count; /* Sweep counter */
int32_t m_sweep_count; /* Sweep counter */
uint8_t m_noise_type; /* Noise generator type */
uint8_t m_noise_reset; /* Noise reset */
uint8_t m_noise_enable; /* Noise enable */
uint8_t m_noise_output; /* Noise output */
uint16_t m_sample_address; /* Sample address */
uint8_t m_audio2_voice; /* Audio 2 voice */
uint8_t m_audio3_sweep; /* Audio 3 sweep */
uint8_t m_audio4_noise; /* Audio 4 noise */
uint8_t m_mono; /* mono */
uint8_t m_voice_data; /* voice data */
uint8_t m_output_volume; /* output volume */
uint8_t m_external_stereo; /* external stereo */
uint8_t m_external_speaker; /* external speaker */

View File

@ -150,7 +150,9 @@ public:
A_SCSP_0 = 0x20000000,
A_SCSP_1 = 0xa0000000,
A_WSWAN_0 = 0x21000000,
A_WSWAN_RAM_0 = 0x21000100,
A_WSWAN_1 = 0xa1000000,
A_WSWAN_RAM_1 = 0xa1000100,
A_VSU_VUE_0 = 0x22000000,
A_VSU_VUE_1 = 0xa2000000,
A_SAA1099_0 = 0x23000000,
@ -389,6 +391,7 @@ public:
template<int Chip> void k054539_map(address_map &map);
template<int Chip> void k053260_map(address_map &map);
template<int Chip> void qsound_map(address_map &map);
template<int Chip> void wswan_map(address_map &map);
template<int Chip> void es5503_map(address_map &map);
template<int Chip> void es5505_map(address_map &map);
template<int Chip> void x1_010_map(address_map &map);
@ -699,6 +702,8 @@ void vgmplay_device::execute_run()
uint32_t size = m_io->read_dword(REG_SIZE);
if (!size)
{
logerror("zero length file\n");
m_pc = 0;
m_state = DONE;
break;
@ -855,7 +860,13 @@ void vgmplay_device::execute_run()
uint32_t loop_offset = m_file->read_dword(0x1c);
if (!loop_offset)
{
m_state = DONE;
if (m_loop)
device_reset();
else
{
logerror("done\n");
m_state = DONE;
}
break;
}
@ -1310,7 +1321,11 @@ void vgmplay_device::execute_run()
case 0xc6:
{
pulse_act_led(LED_WSWAN);
// TODO: Wonderswan memory
uint8_t offset = m_file->read_byte(m_pc + 1);
if (offset & 0x80)
m_io->write_byte(A_WSWAN_RAM_1 + ((offset & 0x7f) << 8) + m_file->read_byte(m_pc + 2), m_file->read_byte(m_pc + 3));
else
m_io->write_byte(A_WSWAN_RAM_0 + ((offset & 0x7f) << 8) + m_file->read_byte(m_pc + 2), m_file->read_byte(m_pc + 3));
m_pc += 4;
break;
}
@ -1455,6 +1470,10 @@ void vgmplay_device::execute_run()
default:
logerror("unhandled code %02x (%02x %02x %02x %02x)\n", code, m_file->read_byte(m_pc + 1), m_file->read_byte(m_pc + 2), m_file->read_byte(m_pc + 3), m_file->read_byte(m_pc + 4));
if (machine().debug_flags & DEBUG_FLAG_ENABLED)
debugger_instruction_hook(m_pc);
m_state = DONE;
m_icount = 0;
break;
@ -1463,21 +1482,7 @@ void vgmplay_device::execute_run()
}
case DONE:
{
static bool done = false;
if (!done && !m_loop)
{
logerror("done\n");
done = true;
}
else if (m_loop)
{
device_reset();
}
else
{
if (machine().debug_flags & DEBUG_FLAG_ENABLED)
debugger_instruction_hook(m_pc);
}
machine().sound().system_mute(1);
m_icount = 0;
break;
}
@ -2359,8 +2364,8 @@ QUICKLOAD_LOAD_MEMBER(vgmplay_state, load_file)
if (version >= 0x170 && header_size >= 0xc0 && r32(0xbc))
logerror("Warning: file requests an unsupported Extra Header\n");
if (version >= 0x171 && header_size >= 0xc4 && r32(0xc0))
logerror("Warning: file requests an unsupported WonderSwan\n");
m_wswan[0]->set_unscaled_clock(version >= 0x161 && header_size >= 0xc4 ? r32(0xc0) & ~0x40000000 : 0);
m_wswan[1]->set_unscaled_clock(version >= 0x161 && header_size >= 0xc4 && (r32(0xc0) & 0x40000000) ? r32(0xc0) & ~0x40000000 : 0);
m_vsu_vue[0]->set_unscaled_clock(version >= 0x161 && header_size >= 0xc8 ? r32(0xc4) & ~0x40000000 : 0);
m_vsu_vue[1]->set_unscaled_clock(version >= 0x161 && header_size >= 0xc8 && (r32(0xc4) & 0x40000000) ? r32(0xc4) & ~0x40000000 : 0);
@ -2398,6 +2403,10 @@ QUICKLOAD_LOAD_MEMBER(vgmplay_state, load_file)
if (child.clock() != 0)
logerror("%s %d\n", child.tag(), child.clock());
//for (auto &stream : machine().sound().streams())
// if (stream->sample_rate() != 0)
// logerror("%s %d\n", stream->device().tag(), stream->sample_rate());
machine().schedule_soft_reset();
return image_init_result::PASS;
@ -2646,6 +2655,8 @@ void vgmplay_state::soundchips_map(address_map &map)
// TODO: scsp
map(vgmplay_device::A_WSWAN_0, vgmplay_device::A_WSWAN_0 + 0xff).w(m_wswan[0], FUNC(wswan_sound_device::port_w));
map(vgmplay_device::A_WSWAN_1, vgmplay_device::A_WSWAN_1 + 0xff).w(m_wswan[1], FUNC(wswan_sound_device::port_w));
map(vgmplay_device::A_WSWAN_RAM_0, vgmplay_device::A_WSWAN_RAM_0 + 0x3fff).ram().share("wswan_ram.0");
map(vgmplay_device::A_WSWAN_RAM_1, vgmplay_device::A_WSWAN_RAM_1 + 0x3fff).ram().share("wswan_ram.1");
map(vgmplay_device::A_VSU_VUE_0, vgmplay_device::A_VSU_VUE_0 + 0x5ff).w(m_vsu_vue[0], FUNC(vboysnd_device::write));
map(vgmplay_device::A_VSU_VUE_1, vgmplay_device::A_VSU_VUE_1 + 0x5ff).w(m_vsu_vue[1], FUNC(vboysnd_device::write));
map(vgmplay_device::A_SAA1099_0, vgmplay_device::A_SAA1099_0 + 1).w(m_saa1099[0], FUNC(saa1099_device::write));
@ -2734,6 +2745,12 @@ void vgmplay_state::qsound_map(address_map &map)
map(0, 0xffffff).r("vgmplay", FUNC(vgmplay_device::qsound_rom_r<Chip>));
}
template<int Chip>
void vgmplay_state::wswan_map(address_map &map)
{
map(0, 0x3fff).ram().share(Chip ? "wswan_ram.1" : "wswan_ram.0");
}
template<int Chip>
void vgmplay_state::es5503_map(address_map &map)
{
@ -3086,12 +3103,13 @@ MACHINE_CONFIG_START(vgmplay_state::vgmplay)
m_scsp[1]->add_route(0, "lspeaker", 1);
m_scsp[1]->add_route(1, "rspeaker", 1);
// TODO: stop wonderswan using machine().sample_rate()
WSWAN_SND(config, m_wswan[0], 0);
m_wswan[0]->set_addrmap(0, &vgmplay_state::wswan_map<0>);
m_wswan[0]->add_route(0, "lspeaker", 0.50);
m_wswan[0]->add_route(1, "rspeaker", 0.50);
WSWAN_SND(config, m_wswan[1], 0);
m_wswan[1]->set_addrmap(0, &vgmplay_state::wswan_map<1>);
m_wswan[1]->add_route(0, "lspeaker", 0.50);
m_wswan[1]->add_route(1, "rspeaker", 0.50);

View File

@ -62,6 +62,11 @@ void wswan_state::wswan_io(address_map &map)
map(0x00, 0xff).rw(FUNC(wswan_state::port_r), FUNC(wswan_state::port_w)); // I/O ports
}
void wswan_state::wswan_snd(address_map &map)
{
map(0x00000, 0x03fff).r(m_vdp, FUNC(wswan_video_device::vram_r));
}
static INPUT_PORTS_START( wswan )
PORT_START("CURSX")
PORT_BIT( 0x1, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_NAME("X1 - Up")
@ -145,7 +150,8 @@ MACHINE_CONFIG_START(wswan_state::wswan)
/* sound hardware */
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
MCFG_DEVICE_ADD(m_sound, WSWAN_SND, 0)
MCFG_DEVICE_ADD(m_sound, WSWAN_SND, 3.072_MHz_XTAL)
MCFG_DEVICE_ADDRESS_MAP(0, wswan_snd)
MCFG_SOUND_ROUTE(0, "lspeaker", 0.50)
MCFG_SOUND_ROUTE(1, "rspeaker", 0.50)

View File

@ -98,6 +98,7 @@ protected:
void wswan_io(address_map &map);
void wswan_mem(address_map &map);
void wswan_snd(address_map &map);
void register_save();
void handle_irqs();

View File

@ -1,4 +1,4 @@
<?xml version="1.0"?>
<?xml version="1.0"?>
<mamelayout version="2">
<!--
Activity LEDs:
@ -85,7 +85,7 @@
<element name="act_label_pokey"><text string="POKEY" align="1"><color red="1.0" green="1.0" blue="1.0" /></text></element>
<element name="act_label_qsound"><text string="QSound™" align="1"><color red="1.0" green="1.0" blue="1.0" /></text></element>
<element name="act_label_scsp"><text string="SCSP" align="1"><color red="0.5" green="0.5" blue="0.5" /></text></element>
<element name="act_label_wswan"><text string="WonderSwan" align="1"><color red="0.5" green="0.5" blue="0.5" /></text></element>
<element name="act_label_wswan"><text string="WonderSwan" align="1"><color red="1.0" green="1.0" blue="1.0" /></text></element>
<element name="act_label_vsu_vue"><text string="VSU-VUE" align="1"><color red="1.0" green="1.0" blue="1.0" /></text></element>
<element name="act_label_saa1099"><text string="SAA1099" align="1"><color red="1.0" green="1.0" blue="1.0" /></text></element>
<element name="act_label_es5503"><text string="ES5503" align="1"><color red="1.0" green="1.0" blue="1.0" /></text></element>