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]

This commit is contained in:
Couriersud 2014-01-13 00:12:39 +00:00
parent 1af170a360
commit a1b3437fc4
7 changed files with 235 additions and 24 deletions

View File

@ -56,6 +56,7 @@
const device_type NETLIST_CORE = &device_creator<netlist_mame_device_t>;
const device_type NETLIST_CPU = &device_creator<netlist_mame_cpu_device_t>;
const device_type NETLIST_SOUND = &device_creator<netlist_mame_sound_device_t>;
const device_type NETLIST_ANALOG_INPUT = &device_creator<netlist_mame_analog_input_t>;
const device_type NETLIST_LOGIC_INPUT = &device_creator<netlist_mame_logic_input_t>;
@ -187,7 +188,7 @@ void netlist_mame_device_t::device_start()
// register additional devices
m_setup->factory().register_device<nld_analog_callback>( "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<nld_analog_callback>( "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<nld_sound *> outdevs = netlist().get_device_list<nld_sound *>();
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<nld_sound>( "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);
}
}

View File

@ -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;

View File

@ -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

View File

@ -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;
};

View File

@ -148,7 +148,7 @@ NETLIB_START(C)
NETLIB_UPDATE_PARAM(C)
{
//step_time(1e-9);
step_time(1.0/48000.0);
}
NETLIB_UPDATE(C)

View File

@ -1067,6 +1067,19 @@ public:
ATTR_COLD void error(const char *format, ...) const;
template<class _C>
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;

View File

@ -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 )