From dd5917522b24ce2d305c47b945b8c059a00cf744 Mon Sep 17 00:00:00 2001 From: Ivan Vangelista Date: Sat, 7 Sep 2013 09:30:29 +0000 Subject: [PATCH] Modernized the sp0250 device. (nw) --- src/emu/sound/sp0250.c | 353 +++++++++++++++++------------------- src/emu/sound/sp0250.h | 36 +++- src/mame/audio/gottlieb.c | 4 +- src/mame/audio/segasnd.c | 2 +- src/mame/drivers/gottlieb.c | 1 - src/mame/drivers/segag80r.c | 1 - 6 files changed, 202 insertions(+), 195 deletions(-) diff --git a/src/emu/sound/sp0250.c b/src/emu/sound/sp0250.c index b52aa6dd66f..7f7b364c949 100644 --- a/src/emu/sound/sp0250.c +++ b/src/emu/sound/sp0250.c @@ -18,7 +18,6 @@ #include "emu.h" #include "sp0250.h" -#include "devlegcy.h" /* standard external clock is 3.12MHz @@ -33,36 +32,84 @@ should be 312, but 312 = 39*8 so it doesn't look right because a divider by 39 i */ #define CLOCK_DIVIDER (7*6*8) -struct sp0250_state +const device_type SP0250 = &device_creator; + +sp0250_device::sp0250_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SP0250, "SP0250", tag, owner, clock, "sp0250", __FILE__), + device_sound_interface(mconfig, *this), + m_amp(0), + m_pitch(0), + m_repeat(0), + m_pcount(0), + m_rcount(0), + m_playing(0), + m_RNG(0), + m_stream(NULL), + m_voiced(0), + m_fifo_pos(0) { - INT16 amp; - UINT8 pitch; - UINT8 repeat; - int pcount, rcount; - int playing; - UINT32 RNG; - sound_stream * stream; - int voiced; - UINT8 fifo[15]; - int fifo_pos; - - device_t *device; - void (*drq)(device_t *device, int state); - - struct + for (int i = 0; i < 15; i++) { - INT16 F, B; - INT16 z1, z2; - } filter[6]; -}; - -INLINE sp0250_state *get_safe_token(device_t *device) -{ - assert(device != NULL); - assert(device->type() == SP0250); - return (sp0250_state *)downcast(device)->token(); + m_fifo[i] = 0; + } + + for (int i = 0; i < 6; i++) + { + m_filter[i].F = 0; + m_filter[i].B = 0; + m_filter[i].z1 = 0; + m_filter[i].z2 = 0; + } } +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void sp0250_device::device_config_complete() +{ + // inherit a copy of the static data + const sp0250_interface *intf = reinterpret_cast(static_config()); + if (intf != NULL) + *static_cast(this) = *intf; + + // or initialize to defaults if none provided + else + { + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sp0250_device::device_start() +{ + const sp0250_interface *intf = reinterpret_cast(static_config()); + + m_RNG = 1; + m_drq = ( intf!= NULL) ? m_drq_callback : NULL; + if (m_drq != NULL) + { + m_drq(this, ASSERT_LINE); + machine().scheduler().timer_pulse(attotime::from_hz(clock()) * CLOCK_DIVIDER, timer_expired_delegate(FUNC(sp0250_device::timer_tick), this)); + } + + m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() / CLOCK_DIVIDER, this); + + save_item(NAME(m_amp)); + save_item(NAME(m_pitch)); + save_item(NAME(m_repeat)); + save_item(NAME(m_pcount)); + save_item(NAME(m_rcount)); + save_item(NAME(m_playing)); + save_item(NAME(m_RNG)); + save_item(NAME(m_voiced)); + save_item(NAME(m_fifo)); + save_item(NAME(m_fifo_pos)); +} static UINT16 sp0250_ga(UINT8 v) { @@ -90,180 +137,63 @@ static INT16 sp0250_gc(UINT8 v) return res; } -static void sp0250_load_values(sp0250_state *sp) +void sp0250_device::load_values() { int f; - sp->filter[0].B = sp0250_gc(sp->fifo[ 0]); - sp->filter[0].F = sp0250_gc(sp->fifo[ 1]); - sp->amp = sp0250_ga(sp->fifo[ 2]); - sp->filter[1].B = sp0250_gc(sp->fifo[ 3]); - sp->filter[1].F = sp0250_gc(sp->fifo[ 4]); - sp->pitch = sp->fifo[ 5]; - sp->filter[2].B = sp0250_gc(sp->fifo[ 6]); - sp->filter[2].F = sp0250_gc(sp->fifo[ 7]); - sp->repeat = sp->fifo[ 8] & 0x3f; - sp->voiced = sp->fifo[ 8] & 0x40; - sp->filter[3].B = sp0250_gc(sp->fifo[ 9]); - sp->filter[3].F = sp0250_gc(sp->fifo[10]); - sp->filter[4].B = sp0250_gc(sp->fifo[11]); - sp->filter[4].F = sp0250_gc(sp->fifo[12]); - sp->filter[5].B = sp0250_gc(sp->fifo[13]); - sp->filter[5].F = sp0250_gc(sp->fifo[14]); - sp->fifo_pos = 0; - if (sp->drq != NULL) - sp->drq(sp->device, ASSERT_LINE); + m_filter[0].B = sp0250_gc(m_fifo[ 0]); + m_filter[0].F = sp0250_gc(m_fifo[ 1]); + m_amp = sp0250_ga(m_fifo[ 2]); + m_filter[1].B = sp0250_gc(m_fifo[ 3]); + m_filter[1].F = sp0250_gc(m_fifo[ 4]); + m_pitch = m_fifo[ 5]; + m_filter[2].B = sp0250_gc(m_fifo[ 6]); + m_filter[2].F = sp0250_gc(m_fifo[ 7]); + m_repeat = m_fifo[ 8] & 0x3f; + m_voiced = m_fifo[ 8] & 0x40; + m_filter[3].B = sp0250_gc(m_fifo[ 9]); + m_filter[3].F = sp0250_gc(m_fifo[10]); + m_filter[4].B = sp0250_gc(m_fifo[11]); + m_filter[4].F = sp0250_gc(m_fifo[12]); + m_filter[5].B = sp0250_gc(m_fifo[13]); + m_filter[5].F = sp0250_gc(m_fifo[14]); + m_fifo_pos = 0; + if (m_drq != NULL) + m_drq(this, ASSERT_LINE); - sp->pcount = 0; - sp->rcount = 0; + m_pcount = 0; + m_rcount = 0; for (f = 0; f < 6; f++) - sp->filter[f].z1 = sp->filter[f].z2 = 0; + m_filter[f].z1 = m_filter[f].z2 = 0; - sp->playing = 1; + m_playing = 1; } -static TIMER_CALLBACK( sp0250_timer_tick ) +TIMER_CALLBACK_MEMBER( sp0250_device::timer_tick ) { - sp0250_state *sp = (sp0250_state *)ptr; - sp->stream->update(); + m_stream->update(); } -static STREAM_UPDATE( sp0250_update ) +WRITE8_MEMBER( sp0250_device::write ) { - sp0250_state *sp = (sp0250_state *)param; - stream_sample_t *output = outputs[0]; - int i; - for (i = 0; i < samples; i++) + m_stream->update(); + if (m_fifo_pos != 15) { - if (sp->playing) - { - INT16 z0; - int f; - - if (sp->voiced) - { - if(!sp->pcount) - z0 = sp->amp; - else - z0 = 0; - } - else - { - // Borrowing the ay noise generation LFSR - if(sp->RNG & 1) - { - z0 = sp->amp; - sp->RNG ^= 0x24000; - } - else - z0 = -sp->amp; - - sp->RNG >>= 1; - } - - for (f = 0; f < 6; f++) - { - z0 += ((sp->filter[f].z1 * sp->filter[f].F) >> 8) - + ((sp->filter[f].z2 * sp->filter[f].B) >> 9); - sp->filter[f].z2 = sp->filter[f].z1; - sp->filter[f].z1 = z0; - } - - // Physical resolution is only 7 bits, but heh - - // max amplitude is 0x0f80 so we have margin to push up the output - output[i] = z0 << 3; - - sp->pcount++; - if (sp->pcount >= sp->pitch) - { - sp->pcount = 0; - sp->rcount++; - if (sp->rcount >= sp->repeat) - sp->playing = 0; - } - } - else - output[i] = 0; - - if (!sp->playing) - { - if(sp->fifo_pos == 15) - sp0250_load_values(sp); - } - } -} - - -static DEVICE_START( sp0250 ) -{ - const struct sp0250_interface *intf = (const struct sp0250_interface *)device->static_config(); - sp0250_state *sp = get_safe_token(device); - - sp->device = device; - sp->RNG = 1; - sp->drq = (intf != NULL) ? intf->drq_callback : NULL; - if (sp->drq != NULL) - { - sp->drq(sp->device, ASSERT_LINE); - device->machine().scheduler().timer_pulse(attotime::from_hz(device->clock()) * CLOCK_DIVIDER, FUNC(sp0250_timer_tick), 0, sp); - } - - sp->stream = device->machine().sound().stream_alloc(*device, 0, 1, device->clock() / CLOCK_DIVIDER, sp, sp0250_update); -} - - -WRITE8_DEVICE_HANDLER( sp0250_w ) -{ - sp0250_state *sp = get_safe_token(device); - sp->stream->update(); - if (sp->fifo_pos != 15) - { - sp->fifo[sp->fifo_pos++] = data; - if (sp->fifo_pos == 15 && sp->drq != NULL) - sp->drq(sp->device, CLEAR_LINE); + m_fifo[m_fifo_pos++] = data; + if (m_fifo_pos == 15 && m_drq != NULL) + m_drq(this, CLEAR_LINE); } else - logerror("%s: overflow SP0250 FIFO\n", device->machine().describe_context()); + logerror("%s: overflow SP0250 FIFO\n", machine().describe_context()); } -UINT8 sp0250_drq_r(device_t *device) +UINT8 sp0250_device::drq_r() { - sp0250_state *sp = get_safe_token(device); - sp->stream->update(); - return (sp->fifo_pos == 15) ? CLEAR_LINE : ASSERT_LINE; -} - - -const device_type SP0250 = &device_creator; - -sp0250_device::sp0250_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : device_t(mconfig, SP0250, "SP0250", tag, owner, clock, "sp0250", __FILE__), - device_sound_interface(mconfig, *this) -{ - m_token = global_alloc_clear(sp0250_state); -} - -//------------------------------------------------- -// device_config_complete - perform any -// operations now that the configuration is -// complete -//------------------------------------------------- - -void sp0250_device::device_config_complete() -{ -} - -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - -void sp0250_device::device_start() -{ - DEVICE_START_NAME( sp0250 )(this); + m_stream->update(); + return (m_fifo_pos == 15) ? CLEAR_LINE : ASSERT_LINE; } //------------------------------------------------- @@ -272,6 +202,65 @@ void sp0250_device::device_start() void sp0250_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) { - // should never get here - fatalerror("sound_stream_update called; not applicable to legacy sound devices\n"); + stream_sample_t *output = outputs[0]; + int i; + for (i = 0; i < samples; i++) + { + if (m_playing) + { + INT16 z0; + int f; + + if (m_voiced) + { + if(!m_pcount) + z0 = m_amp; + else + z0 = 0; + } + else + { + // Borrowing the ay noise generation LFSR + if(m_RNG & 1) + { + z0 = m_amp; + m_RNG ^= 0x24000; + } + else + z0 = -m_amp; + + m_RNG >>= 1; + } + + for (f = 0; f < 6; f++) + { + z0 += ((m_filter[f].z1 * m_filter[f].F) >> 8) + + ((m_filter[f].z2 * m_filter[f].B) >> 9); + m_filter[f].z2 = m_filter[f].z1; + m_filter[f].z1 = z0; + } + + // Physical resolution is only 7 bits, but heh + + // max amplitude is 0x0f80 so we have margin to push up the output + output[i] = z0 << 3; + + m_pcount++; + if (m_pcount >= m_pitch) + { + m_pcount = 0; + m_rcount++; + if (m_rcount >= m_repeat) + m_playing = 0; + } + } + else + output[i] = 0; + + if (!m_playing) + { + if(m_fifo_pos == 15) + load_values(); + } + } } diff --git a/src/emu/sound/sp0250.h b/src/emu/sound/sp0250.h index 1814cb2018f..7cb01c97691 100644 --- a/src/emu/sound/sp0250.h +++ b/src/emu/sound/sp0250.h @@ -5,21 +5,21 @@ struct sp0250_interface { - void (*drq_callback)(device_t *device, int state); + void (*m_drq_callback)(device_t *device, int state); }; -DECLARE_WRITE8_DEVICE_HANDLER( sp0250_w ); -UINT8 sp0250_drq_r(device_t *device); class sp0250_device : public device_t, - public device_sound_interface + public device_sound_interface, + public sp0250_interface { public: sp0250_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - ~sp0250_device() { global_free(m_token); } + ~sp0250_device() {} - // access to legacy token - void *token() const { assert(m_token != NULL); return m_token; } + DECLARE_WRITE8_MEMBER( write ); + UINT8 drq_r(); + protected: // device-level overrides virtual void device_config_complete(); @@ -27,9 +27,29 @@ protected: // sound stream update overrides virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + private: // internal state - void *m_token; + INT16 m_amp; + UINT8 m_pitch; + UINT8 m_repeat; + int m_pcount, m_rcount; + int m_playing; + UINT32 m_RNG; + sound_stream * m_stream; + int m_voiced; + UINT8 m_fifo[15]; + int m_fifo_pos; + void (*m_drq)(device_t *device, int state); + + struct + { + INT16 F, B; + INT16 z1, z2; + } m_filter[6]; + + void load_values(); + TIMER_CALLBACK_MEMBER( timer_tick ); }; extern const device_type SP0250; diff --git a/src/mame/audio/gottlieb.c b/src/mame/audio/gottlieb.c index bafddf95f81..6419170cca2 100644 --- a/src/mame/audio/gottlieb.c +++ b/src/mame/audio/gottlieb.c @@ -771,7 +771,7 @@ WRITE8_MEMBER( gottlieb_sound_r2_device::nmi_rate_w ) CUSTOM_INPUT_MEMBER( gottlieb_sound_r2_device::speech_drq_custom_r ) { - return sp0250_drq_r(m_sp0250); + return m_sp0250->drq_r(); } @@ -837,7 +837,7 @@ WRITE8_MEMBER( gottlieb_sound_r2_device::speech_control_w ) // bit 6 = speech chip DATA PRESENT pin; high then low to make the chip read data if ((previous & 0x40) == 0 && (data & 0x40) != 0) - sp0250_w(m_sp0250, space, 0, m_sp0250_latch); + m_sp0250->write(space, 0, m_sp0250_latch); // bit 7 goes to the speech chip RESET pin if ((previous ^ data) & 0x80) diff --git a/src/mame/audio/segasnd.c b/src/mame/audio/segasnd.c index 658073fe10e..5faaaeb768f 100644 --- a/src/mame/audio/segasnd.c +++ b/src/mame/audio/segasnd.c @@ -340,7 +340,7 @@ ADDRESS_MAP_END static ADDRESS_MAP_START( speech_portmap, AS_IO, 8, driver_device ) AM_RANGE(0x00, 0xff) AM_DEVREAD_LEGACY("segaspeech", speech_rom_r) - AM_RANGE(0x00, 0xff) AM_DEVWRITE_LEGACY("speech", sp0250_w) + AM_RANGE(0x00, 0xff) AM_DEVWRITE("speech", sp0250_device, write) AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_DEVREADWRITE_LEGACY("segaspeech", speech_p1_r, speech_p1_w) AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_DEVWRITE_LEGACY("segaspeech", speech_p2_w) AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_DEVREAD_LEGACY("segaspeech", speech_t0_r) diff --git a/src/mame/drivers/gottlieb.c b/src/mame/drivers/gottlieb.c index f4b3993d5cd..ac32f735c41 100644 --- a/src/mame/drivers/gottlieb.c +++ b/src/mame/drivers/gottlieb.c @@ -199,7 +199,6 @@ VBlank duration: 1/VSYNC * (16/256) = 1017.6 us #include "sound/ay8910.h" #include "sound/dac.h" #include "sound/samples.h" -#include "sound/sp0250.h" #include "machine/nvram.h" #include "includes/gottlieb.h" diff --git a/src/mame/drivers/segag80r.c b/src/mame/drivers/segag80r.c index d4be9de0dc5..f270626d7aa 100644 --- a/src/mame/drivers/segag80r.c +++ b/src/mame/drivers/segag80r.c @@ -109,7 +109,6 @@ #include "sound/dac.h" #include "sound/sn76496.h" #include "sound/samples.h" -#include "sound/sp0250.h" #include "audio/segasnd.h" #include "machine/i8255.h" #include "machine/segacrpt.h"