From 16cc6c9d80cfacf252e36232ae27d76a629ed5b6 Mon Sep 17 00:00:00 2001 From: angelosa Date: Thu, 15 May 2025 22:03:06 +0200 Subject: [PATCH] sega/dsb2.cpp: add basic MPEG playback --- src/mame/sega/dsb2.cpp | 167 +++++++++++++++++++++++++++++++++++++---- src/mame/sega/dsb2.h | 37 ++++++--- 2 files changed, 177 insertions(+), 27 deletions(-) diff --git a/src/mame/sega/dsb2.cpp b/src/mame/sega/dsb2.cpp index 652f98e3eca..04ab2ffcc95 100644 --- a/src/mame/sega/dsb2.cpp +++ b/src/mame/sega/dsb2.cpp @@ -1,12 +1,10 @@ // license:BSD-3-Clause // copyright-holders: -/*************************************************************************** +/************************************************************************************************** - Sega Z80 Digital Sound Board +Sega Digital Sound Board 2 - used for Model 1/2/3 - -***************************************************************************/ +**************************************************************************************************/ #include "emu.h" @@ -28,14 +26,15 @@ dsb2_device::dsb2_device(const machine_config &mconfig, const char *tag, device_ m_mp_end(0), m_mp_vol(0x7f), m_mp_pan(0), - m_mp_state(0), m_lp_start(0), m_lp_end(0), m_start(0), m_end(0), m_mp_pos(0), m_audio_pos(0), - m_audio_avail(0) + m_audio_avail(0), + m_command(mpeg_command_t::IDLE), + m_player(mpeg_player_t::NOT_PLAYING) { } @@ -47,7 +46,7 @@ void dsb2_device::dsb2_map(address_map &map) // map(0xd00001) system control? // map(0xd20001) flsbeats reads here // map(0xe00001) acknowledge FIFO writes? -// map(0xe00003) MPEG FIFO writes + map(0xe00003, 0xe00003).w(FUNC(dsb2_device::fifo_w)); // MPEG status map(0xe80001, 0xe80001).lr8(NAME([] () { return 0x01; })); map(0xf00000, 0xf1ffff).ram(); @@ -56,7 +55,6 @@ void dsb2_device::dsb2_map(address_map &map) void dsb2_device::device_add_mconfig(machine_config &config) { // TODO: unknown clocks - // TODO: 1 kHz timer for irq2 M68000(config, m_ourcpu, 8000000); m_ourcpu->set_addrmap(AS_PROGRAM, &dsb2_device::dsb2_map); @@ -75,11 +73,14 @@ void dsb2_device::device_start() m_decoder.reset(new mpeg_audio(&m_mpeg_rom[0], mpeg_audio::L2, false, 0)); stream_alloc(0, 2, 32000); + m_timer_1kHz = timer_alloc(FUNC(dsb2_device::timer_irq_cb), this); + save_item(NAME(m_mp_start)); save_item(NAME(m_mp_end)); save_item(NAME(m_mp_vol)); save_item(NAME(m_mp_pan)); - save_item(NAME(m_mp_state)); +// save_item(NAME(m_command)); +// save_item(NAME(m_player)); save_item(NAME(m_lp_start)); save_item(NAME(m_lp_end)); save_item(NAME(m_start)); @@ -95,11 +96,13 @@ void dsb2_device::device_reset() m_audio_pos = m_audio_avail = 0; std::fill(std::begin(m_audio_buf), std::end(m_audio_buf), 0); m_mp_vol = 0x7f; - m_mp_state = 0; + m_command = IDLE; + m_player = NOT_PLAYING; m_uart->write_cts(0); -} + m_timer_1kHz->adjust(attotime::from_hz(1000), 0, attotime::from_hz(1000)); +} void dsb2_device::device_stop() { @@ -116,10 +119,144 @@ void dsb2_device::output_txd(int state) m_rxd_handler(state); } +TIMER_CALLBACK_MEMBER(dsb2_device::timer_irq_cb) +{ + m_ourcpu->set_input_line(2, HOLD_LINE); +} + +void dsb2_device::fifo_w(offs_t offset, u8 data) +{ + switch(m_command) + { + case mpeg_command_t::START_ADDRESS_HI: + m_start &= 0x00ffff; + m_start |= (uint32_t)data << 16; + m_command = mpeg_command_t::START_ADDRESS_MD; + break; + case mpeg_command_t::START_ADDRESS_MD: + m_start &= 0xff00ff; + m_start |= (uint32_t)data << 8; + m_command = mpeg_command_t::START_ADDRESS_LO; + break; + case mpeg_command_t::START_ADDRESS_LO: + m_start &= 0xffff00; + m_start |= data; + + m_mp_start = m_start; + m_command = mpeg_command_t::IDLE; + break; + + case mpeg_command_t::END_ADDRESS_HI: + m_end &= 0x00ffff; + m_end |= (uint32_t)data << 16; + m_command = mpeg_command_t::END_ADDRESS_MD; + break; + case mpeg_command_t::END_ADDRESS_MD: + m_end &= 0xff00ff; + m_end |= (uint32_t)data << 8; + m_command = mpeg_command_t::END_ADDRESS_LO; + break; + case mpeg_command_t::END_ADDRESS_LO: + m_end &= 0xffff00; + m_end |= data; + + m_mp_end = m_end; + m_command = mpeg_command_t::IDLE; + break; + + case mpeg_command_t::IDLE: + default: + { + if ((data & 0xfe) == 0x14) + m_command = mpeg_command_t::START_ADDRESS_HI; + if ((data & 0xfe) == 0x24) + m_command = mpeg_command_t::END_ADDRESS_HI; + if ((data & 0xfe) == 0x74) + { + m_mp_pos = m_mp_start * 8; + m_player = mpeg_player_t::PLAYING; + } + + if ((data & 0xfe) == 0x84) + { + m_player = mpeg_player_t::NOT_PLAYING; + m_audio_pos = m_audio_avail = 0; + } + } + } +} + void dsb2_device::sound_stream_update(sound_stream &stream) { - //int samples = stream.samples(); - //int sampindex = 0; + int samples = stream.samples(); + int sampindex = 0; + for (;;) + { + while (samples && (m_audio_pos < m_audio_avail)) + { + switch (m_mp_pan) + { + case 0: // stereo + stream.put_int(0, sampindex, m_audio_buf[m_audio_pos*2] * m_mp_vol, 32768 * 128); + stream.put_int(1, sampindex, m_audio_buf[m_audio_pos*2+1] * m_mp_vol, 32768 * 128); + sampindex++; + break; - // ... + case 1: // left only + stream.put_int(0, sampindex, m_audio_buf[m_audio_pos*2] * m_mp_vol, 32768 * 128); + stream.put_int(1, sampindex, m_audio_buf[m_audio_pos*2] * m_mp_vol, 32768 * 128); + sampindex++; + break; + + case 2: // right only + stream.put_int(0, sampindex, m_audio_buf[m_audio_pos*2+1] * m_mp_vol, 32768 * 128); + stream.put_int(1, sampindex, m_audio_buf[m_audio_pos*2+1] * m_mp_vol, 32768 * 128); + sampindex++; + break; + } + m_audio_pos++; + samples--; + } + + if (!samples) + { + break; + } + + if (m_player == mpeg_player_t::NOT_PLAYING) + { + break; + } + else + { + int sample_rate, channel_count; + bool const ok = m_decoder->decode_buffer(m_mp_pos, m_mp_end * 8, m_audio_buf, m_audio_avail, sample_rate, channel_count); + + if (ok) + { + m_audio_pos = 0; + } + else + { + //if (m_mp_state == 2) + //{ + // if (m_mp_pos == m_lp_start * 8) + // { + // // We're looping on un-decodable crap, abort abort abort + // m_mp_state = 0; + // } + // m_mp_pos = m_lp_start * 8; +// + // if (m_lp_end) + // { + // m_mp_end = m_lp_end; + // } + //} + //else + { + m_player = mpeg_player_t::NOT_PLAYING; + } + } + } + } } diff --git a/src/mame/sega/dsb2.h b/src/mame/sega/dsb2.h index 894b8d2aaba..703eae29d90 100644 --- a/src/mame/sega/dsb2.h +++ b/src/mame/sega/dsb2.h @@ -13,10 +13,6 @@ #include -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** - class dsb2_device : public device_t, public device_sound_interface { public: @@ -47,19 +43,36 @@ private: std::unique_ptr m_decoder; int16_t m_audio_buf[1152*2]; - uint32_t m_mp_start, m_mp_end, m_mp_vol, m_mp_pan, m_mp_state, m_lp_start, m_lp_end, m_start, m_end; + uint32_t m_mp_start, m_mp_end, m_mp_vol, m_mp_pan, m_lp_start, m_lp_end, m_start, m_end; int32_t m_mp_pos, m_audio_pos, m_audio_avail; + emu_timer *m_timer_1kHz; + TIMER_CALLBACK_MEMBER(timer_irq_cb); + void output_txd(int state); -// void mpeg_trigger_w(uint8_t data); -// void mpeg_start_w(offs_t offset, uint8_t data); -// void mpeg_end_w(offs_t offset, uint8_t data); -// void mpeg_volume_w(uint8_t data); -// void mpeg_stereo_w(uint8_t data); -// uint8_t mpeg_pos_r(offs_t offset); - void dsb2_map(address_map &map) ATTR_COLD; + + enum mpeg_command_t : u8 { + IDLE, + START_ADDRESS_HI, + START_ADDRESS_MD, + START_ADDRESS_LO, + END_ADDRESS_HI, + END_ADDRESS_MD, + END_ADDRESS_LO + }; + + enum mpeg_player_t : u8 { + NOT_PLAYING, + PLAYING + }; + + mpeg_command_t m_command; + mpeg_player_t m_player; + + + void fifo_w(offs_t offset, u8 data); };