From a1b3437fc42bd2260707f09813a8d788381ae702 Mon Sep 17 00:00:00 2001 From: Couriersud Date: Mon, 13 Jan 2014 00:12:39 +0000 Subject: [PATCH] Created a mame sound device for netlist. Fixed an issue causing wild oscillations. Currently, pong has sample code for using the sound device. Uncomment "TEST_SOUND" in pong.c to hear a constant sound from a 7400 multivibrator. Sound is still WIP, but the proof of concept has been done. [Couriersud] --- src/emu/machine/netlist.c | 79 ++++++++++++++++++++++- src/emu/machine/netlist.h | 94 +++++++++++++++++++++++----- src/emu/netlist/analog/nld_solver.c | 28 ++++++++- src/emu/netlist/analog/nld_solver.h | 2 + src/emu/netlist/analog/nld_twoterm.c | 2 +- src/emu/netlist/nl_base.h | 13 ++++ src/mame/drivers/pong.c | 41 +++++++++++- 7 files changed, 235 insertions(+), 24 deletions(-) diff --git a/src/emu/machine/netlist.c b/src/emu/machine/netlist.c index 913fda283c2..38de534476c 100644 --- a/src/emu/machine/netlist.c +++ b/src/emu/machine/netlist.c @@ -56,6 +56,7 @@ const device_type NETLIST_CORE = &device_creator; const device_type NETLIST_CPU = &device_creator; +const device_type NETLIST_SOUND = &device_creator; const device_type NETLIST_ANALOG_INPUT = &device_creator; const device_type NETLIST_LOGIC_INPUT = &device_creator; @@ -187,7 +188,7 @@ void netlist_mame_device_t::device_start() // register additional devices - m_setup->factory().register_device( "NETDEV_CALLBACK", "nld_analog_callback", "-"); + nl_register_devices(); m_setup_func(*m_setup); @@ -351,6 +352,12 @@ void netlist_mame_cpu_device_t::device_start() m_icountptr = &m_icount; } + +void netlist_mame_cpu_device_t::nl_register_devices() +{ + setup().factory().register_device( "NETDEV_CALLBACK", "nld_analog_callback", "-"); +} + ATTR_COLD UINT64 netlist_mame_cpu_device_t::execute_clocks_to_cycles(UINT64 clocks) const { return clocks; @@ -404,3 +411,73 @@ ATTR_HOT void netlist_mame_cpu_device_t::execute_run() update_time_x(); } } + +// ---------------------------------------------------------------------------------------- +// netlist_mame_sound_device_t +// ---------------------------------------------------------------------------------------- + +netlist_mame_sound_device_t::netlist_mame_sound_device_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : netlist_mame_device_t(mconfig, NETLIST_CPU, "Netlist sound device", tag, owner, clock, "netlist_sound", __FILE__), + device_sound_interface(mconfig, *this) +{ +} + + +void netlist_mame_sound_device_t::device_start() +{ + netlist_mame_device_t::device_start(); + + LOG_DEV_CALLS(("device_start %s\n", tag())); + + netlist_list_t outdevs = netlist().get_device_list(); + if (outdevs.count() == 0) + fatalerror("No output devices"); + + m_num_outputs = outdevs.count(); + m_num_inputs = 0; + + /* resort channels */ + for (int i=0; i < MAX_OUT; i++) m_out[i] = NULL; + for (int i=0; i < m_num_outputs; i++) + { + int chan = outdevs[i]->m_channel.Value(); + if (chan < 0 || chan >= MAX_OUT || chan >= outdevs.count()) + fatalerror("illegal channel number"); + m_out[chan] = outdevs[i]; + m_out[chan]->m_sample = netlist_time::from_hz(clock()); + m_out[chan]->m_buffer = NULL; + } + + /* initialize the stream(s) */ + m_stream = machine().sound().stream_alloc(*this, m_num_inputs, m_num_outputs, clock()); + +} + +void netlist_mame_sound_device_t::nl_register_devices() +{ + setup().factory().register_device( "NETDEV_SOUND_OUT", "nld_sound", "+CHAN"); +} + + +void netlist_mame_sound_device_t::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + for (int i=0; i < m_num_outputs; i++) + { + m_out[i]->m_buffer = outputs[i]; + } + + netlist_time cur = netlist().time(); + + //printf("current time %f\n", netlist().time().as_double()); + + netlist().process_queue(netlist_time::from_raw(m_div) * samples); + + cur += (netlist_time::from_raw(m_div) * samples); + + for (int i=0; i < m_num_outputs; i++) + { + m_out[i]->sound_update(cur); + m_out[i]->buffer_reset(cur); + } +} + diff --git a/src/emu/machine/netlist.h b/src/emu/machine/netlist.h index 514371879b1..5e5d702cfcf 100644 --- a/src/emu/machine/netlist.h +++ b/src/emu/machine/netlist.h @@ -56,13 +56,6 @@ // MAME specific configuration -#define MCFG_NETLIST_ADD(_tag, _setup, _clock ) \ - MCFG_DEVICE_ADD(_tag, NETLIST_CPU, _clock) \ - MCFG_NETLIST_SETUP(_setup) - -#define MCFG_NETLIST_REPLACE(_tag, _setup) \ - MCFG_DEVICE_REPLACE(_tag, NETLIST_CPU, NETLIST_CLOCK) \ - MCFG_NETLIST_SETUP(_setup) #define MCFG_NETLIST_SETUP(_setup) \ netlist_mame_device_t::static_set_constructor(*device, NETLIST_NAME(_setup)); @@ -102,6 +95,11 @@ #define NETDEV_ANALOG_CALLBACK_MEMBER(_name) \ void _name(const double data, const attotime &time) +#define NETDEV_SOUND_OUT(_name, _v) \ + NET_REGISTER_DEV(sound, _name) \ + NETDEV_PARAM(_name.CHAN, _v) + + class netlist_mame_device_t; class netlist_mame_t : public netlist_base_t @@ -155,7 +153,11 @@ public: int m_icount; protected: - // device_t overrides + // Custom to netlist ... + + virtual void nl_register_devices() { }; + + // device_t overrides virtual void device_config_complete(); virtual void device_start(); virtual void device_stop(); @@ -205,7 +207,11 @@ public: static void static_set_constructor(device_t &device, void (*setup_func)(netlist_setup_t &)); protected: + // netlist_mame_device_t + virtual void nl_register_devices(); + // device_t overrides + //virtual void device_config_complete(); virtual void device_start(); //virtual void device_stop(); @@ -259,6 +265,51 @@ private: }; +class nld_sound; + +// ---------------------------------------------------------------------------------------- +// netlist_mame_sound_device_t +// ---------------------------------------------------------------------------------------- + +class netlist_mame_sound_device_t : public netlist_mame_device_t, + public device_sound_interface +{ +public: + + // construction/destruction + netlist_mame_sound_device_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~netlist_mame_sound_device_t() {} + + static void static_set_constructor(device_t &device, void (*setup_func)(netlist_setup_t &)); + + // device_sound_interface overrides + + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +protected: + // netlist_mame_device_t + virtual void nl_register_devices(); + + // device_t overrides + + //virtual void device_config_complete(); + virtual void device_start(); + //virtual void device_stop(); + //virtual void device_reset(); + //virtual void device_post_load(); + //virtual void device_pre_save(); + //virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + + static const int MAX_OUT = 10; + nld_sound *m_out[MAX_OUT]; + sound_stream *m_stream; + int m_num_inputs; + int m_num_outputs; + +}; + // ---------------------------------------------------------------------------------------- // netlist_mame_sub_interface // ---------------------------------------------------------------------------------------- @@ -407,6 +458,8 @@ public: ATTR_COLD void start() { register_input("IN", m_in); + register_param("CHAN", m_channel, 0); + m_sample = netlist_time::from_hz(1); //sufficiently big enough } ATTR_COLD void reset() @@ -414,13 +467,11 @@ public: m_cur = 0; m_last_pos = 0; m_last_buffer = netlist_time::zero; - m_sample = netlist_time::zero; // FIXME: divide by zero } - ATTR_HOT void sound_update() + ATTR_HOT void sound_update(const netlist_time upto) { - netlist_time current = netlist().time(); - int pos = (current - m_last_buffer) / m_sample; + int pos = (upto - m_last_buffer) / m_sample; if (pos >= BUFSIZE) netlist().error("sound %s: exceeded BUFSIZE\n", name().cstr()); while (m_last_pos < pos ) @@ -432,23 +483,32 @@ public: ATTR_HOT void update() { double val = INPANALOG(m_in); - sound_update(); - m_cur = val; + sound_update(netlist().time()); + m_cur = val * 1000; } + ATTR_HOT void buffer_reset(netlist_time upto) + { + m_last_pos = 0; + m_last_buffer = upto; + } + + netlist_param_int_t m_channel; + stream_sample_t *m_buffer; + netlist_time m_sample; + private: netlist_analog_input_t m_in; - netlist_time m_sample; - double m_cur; + stream_sample_t m_cur; int m_last_pos; netlist_time m_last_buffer; - stream_sample_t m_buffer[BUFSIZE]; }; // device type definition extern const device_type NETLIST_CORE; extern const device_type NETLIST_CPU; +extern const device_type NETLIST_SOUND; extern const device_type NETLIST_ANALOG_INPUT; extern const device_type NETLIST_LOGIC_INPUT; diff --git a/src/emu/netlist/analog/nld_solver.c b/src/emu/netlist/analog/nld_solver.c index dfbbdf46786..c10da4f0cd5 100644 --- a/src/emu/netlist/analog/nld_solver.c +++ b/src/emu/netlist/analog/nld_solver.c @@ -153,6 +153,19 @@ ATTR_HOT inline bool netlist_matrix_solver_t::solve() m_resched = false; + if (USE_ALTERNATE_SCHEDULING) + { + netlist_time now = owner().netlist().time(); + netlist_time delta = now - m_last_step; + if (delta >= netlist_time::from_nsec(5)) // always update capacitors + { + NL_VERBOSE_OUT(("Step!\n")); + /* update all terminals for new time step */ + m_last_step = now; + step(delta); + } + } + if (is_dynamic()) { int this_resched; @@ -202,6 +215,10 @@ ATTR_HOT void netlist_matrix_solver_t::schedule() // update_inputs(); } +ATTR_COLD void netlist_matrix_solver_t::reset() +{ + m_last_step = netlist_time::zero; +} // ---------------------------------------------------------------------------------------- // solver @@ -272,6 +289,8 @@ NETLIB_START(solver) NETLIB_RESET(solver) { m_last_step = netlist_time::zero; + for (int i = 0; i < m_mat_solvers.count(); i++) + m_mat_solvers[i]->reset(); } @@ -300,7 +319,11 @@ NETLIB_UPDATE(solver) bool global_resched = false; bool this_resched[100]; - if (delta >= m_inc) + if (delta < m_inc) + do_full = true; // we have been called between updates + + //FIXME: make this a parameter + if (!USE_ALTERNATE_SCHEDULING && delta >= netlist_time::from_nsec(5)) // always update capacitors { NL_VERBOSE_OUT(("Step!\n")); /* update all terminals for new time step */ @@ -309,8 +332,7 @@ NETLIB_UPDATE(solver) { (*e)->step(delta); } - } else - do_full = true; // we have been called inbetween updates + } #if HAS_OPENMP && USE_OPENMP diff --git a/src/emu/netlist/analog/nld_solver.h b/src/emu/netlist/analog/nld_solver.h index 9bf07f9f66f..4bb5ce98883 100644 --- a/src/emu/netlist/analog/nld_solver.h +++ b/src/emu/netlist/analog/nld_solver.h @@ -46,6 +46,7 @@ public: ATTR_HOT inline bool is_timestep() { return m_steps.count() > 0; } ATTR_HOT inline const NETLIB_NAME(solver) &owner() const; + ATTR_COLD void reset(); double m_accuracy; double m_convergence_factor; @@ -57,6 +58,7 @@ private: netlist_core_terminal_t::list_t m_inps; dev_list_t m_steps; bool m_resched; + netlist_time m_last_step; NETLIB_NAME(solver) *m_owner; }; diff --git a/src/emu/netlist/analog/nld_twoterm.c b/src/emu/netlist/analog/nld_twoterm.c index 55c459537b9..61891bfe599 100644 --- a/src/emu/netlist/analog/nld_twoterm.c +++ b/src/emu/netlist/analog/nld_twoterm.c @@ -148,7 +148,7 @@ NETLIB_START(C) NETLIB_UPDATE_PARAM(C) { - //step_time(1e-9); + step_time(1.0/48000.0); } NETLIB_UPDATE(C) diff --git a/src/emu/netlist/nl_base.h b/src/emu/netlist/nl_base.h index 3741d71f54b..d18ab916679 100644 --- a/src/emu/netlist/nl_base.h +++ b/src/emu/netlist/nl_base.h @@ -1067,6 +1067,19 @@ public: ATTR_COLD void error(const char *format, ...) const; + template + netlist_list_t<_C> get_device_list() + { + netlist_list_t<_C> tmp; + for (tagmap_devices_t::entry_t *entry = m_devices.first(); entry != NULL; entry = m_devices.next(entry)) + { + _C dev = dynamic_cast<_C>(entry->object()); + if (dev != NULL) + tmp.add(dev); + } + return tmp; + } + tagmap_devices_t m_devices; netlist_net_t::list_t m_nets; diff --git a/src/mame/drivers/pong.c b/src/mame/drivers/pong.c index 014c3c0a9e8..cc5047cfb34 100644 --- a/src/mame/drivers/pong.c +++ b/src/mame/drivers/pong.c @@ -20,6 +20,8 @@ TODO: #include "video/fixfreq.h" #include "astring.h" +//#define TEST_SOUND + /* * H count width to 512 * Reset at 1C6 = 454 @@ -705,6 +707,34 @@ static NETLIST_START(pong_fast) NETLIST_END() +#ifdef TESTSOUND +static NETLIST_START(test) + + /* + * Astable multivibrator using two 7400 gates (or inverters) + * + */ + + /* Standard stuff */ + + NETDEV_SOLVER(Solver) + NETDEV_PARAM(Solver.FREQ, 48000) + + // astable NAND Multivibrator + NETDEV_R(R1, 1000) + NETDEV_C(C1, 1e-6) + TTL_7400_NAND(n1,R1.1,R1.1) + TTL_7400_NAND(n2,R1.2,R1.2) + NET_C(n1.Q, R1.2) + NET_C(n2.Q, C1.1) + NET_C(C1.2, R1.1) + + NETDEV_SOUND_OUT(CH0, 0) + NET_C(CH0.IN, n2.Q) + +NETLIST_END() +#endif + void pong_state::machine_start() { } @@ -758,8 +788,9 @@ INPUT_PORTS_END static MACHINE_CONFIG_START( pong, pong_state ) /* basic machine hardware */ - //MCFG_NETLIST_ADD("maincpu", pong, MASTER_CLOCK * 8) - MCFG_NETLIST_ADD("maincpu", pong, NETLIST_CLOCK) + MCFG_DEVICE_ADD("maincpu", NETLIST_CPU, NETLIST_CLOCK) + MCFG_NETLIST_SETUP(pong) + MCFG_NETLIST_ANALOG_INPUT("maincpu", "vr0", "ic_b9_R.R") MCFG_NETLIST_ANALOG_INPUT_MULT_OFFSET(1.0 / 100.0 * RES_K(50), RES_K(56) ) MCFG_NETLIST_ANALOG_INPUT("maincpu", "vr1", "ic_a9_R.R") @@ -782,6 +813,12 @@ static MACHINE_CONFIG_START( pong, pong_state ) MCFG_SOUND_ADD("dac", DAC, 48000) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) +#ifdef TEST_SOUND + MCFG_SOUND_ADD("snd_test", NETLIST_SOUND, 24000) + MCFG_NETLIST_SETUP(test) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) +#endif + MACHINE_CONFIG_END static MACHINE_CONFIG_DERIVED( pongf, pong )