summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2018-05-01 21:35:58 +1000
committer Vas Crabb <vas@vastheman.com>2018-05-01 21:35:58 +1000
commit384bf0e5100c1fa005b4814dc950e3cbcbbb76a9 (patch)
tree1b993c2dd0e9645eba62dc492814931f7555dced /src/emu
parent547086658208e3aa715ab74d520ad0b8e4d7fa22 (diff)
Route sound relative to current device.
Also, look Ma - no magic prologue! Slot card additions run in the context of the slot itself, which isn't entirely intuitive. Slot configuration needs a bunch of other cleanup anyway.
Diffstat (limited to 'src/emu')
-rw-r--r--src/emu/devfind.h67
-rw-r--r--src/emu/device.cpp8
-rw-r--r--src/emu/disound.cpp118
-rw-r--r--src/emu/disound.h31
-rw-r--r--src/emu/emufwd.h3
5 files changed, 149 insertions, 78 deletions
diff --git a/src/emu/devfind.h b/src/emu/devfind.h
index 90e7e4f3dba..cc15c201af9 100644
--- a/src/emu/devfind.h
+++ b/src/emu/devfind.h
@@ -20,6 +20,7 @@
#include <functional>
#include <iterator>
#include <stdexcept>
+#include <string>
#include <type_traits>
//**************************************************************************
@@ -249,6 +250,15 @@ public:
/// otherwise.
virtual bool findit(bool isvalidation = false) = 0;
+ /// \brief Clear temporary binding from configuration
+ ///
+ /// Concrete derived classes must implement this member function.
+ /// Object finders may allow temporary binding to the anticipated
+ /// target during configuration. This needs to be cleared to ensure
+ /// the correct target is found if a device further up the hierarchy
+ /// subsequently removes or replaces devices.
+ virtual void end_configuration() = 0;
+
/// \brief Get search tag
///
/// Returns the search tag.
@@ -287,10 +297,8 @@ public:
/// Some objects must be resolved before memory maps are loaded
/// (devices for instance), some after (memory shares for
/// instance).
- ///
/// \return True if the target object has to be resolved before
- /// memory maps are loaded
-
+ /// memory maps are loaded
virtual bool is_pre_map() const { return false; }
/// \brief Dummy tag always treated as not found
@@ -412,6 +420,14 @@ template <class ObjectClass, bool Required>
class object_finder_base : public finder_base
{
public:
+ /// \brief Clear temporary binding from configuration
+ ///
+ /// Object finders may allow temporary binding to the anticipated
+ /// target during configuration. This needs to be cleared to ensure
+ /// the correct target is found if a device further up the hierarchy
+ /// subsequently removes or replaces devices.
+ virtual void end_configuration() override { m_target = nullptr; }
+
/// \brief Get pointer to target object
/// \return Pointer to target object if found, or nullptr otherwise.
ObjectClass *target() const { return m_target; }
@@ -494,12 +510,53 @@ public:
/// Some objects must be resolved before memory maps are loaded
/// (devices for instance), some after (memory shares for
/// instance).
- ///
/// \return True if the target object has to be resolved before
- /// memory maps are loaded
+ /// memory maps are loaded.
virtual bool is_pre_map() const override { return true; }
+ /// \brief Set target during configuration
+ ///
+ /// During configuration, device_finder instances may be assigned
+ /// a reference to the anticipated target device to avoid the need
+ /// for tempories during configuration. Normal resolution will
+ /// still happen after machine configuration is completed to ensure
+ /// device removal/replacement is handled properly.
+ /// \param [in] device Reference to anticipated target device.
+ /// \return The same reference supplied by the caller.
+ template <typename T>
+ std::enable_if_t<std::is_convertible<T *, DeviceClass *>::value, T &> operator=(T &device)
+ {
+ assert(is_expected_tag(device));
+ this->m_target = &device;
+ return device;
+ }
+
private:
+ template <typename T> struct is_device_implementation
+ { static constexpr bool value = std::is_base_of<device_t, T>::value; };
+ template <typename T> struct is_device_interface
+ { static constexpr bool value = std::is_base_of<device_interface, T>::value && !is_device_implementation<T>::value; };
+
+ /// \brief Check that device implementation has expected tag
+ /// \param [in] device Reference to device.
+ /// \return True if supplied device matches the configured target
+ /// tag, or false otherwise.
+ template <typename T>
+ std::enable_if_t<is_device_implementation<T>::value, bool> is_expected_tag(T const &device) const
+ {
+ return this->m_base.get().subtag(this->m_tag) == device.tag();
+ }
+
+ /// \brief Check that device mixin has expected tag
+ /// \param [in] device Reference to interface/mixin.
+ /// \return True if supplied mixin matches the configured target
+ /// tag, or false otherwise.
+ template <typename T>
+ std::enable_if_t<is_device_interface<T>::value, bool> is_expected_tag(T const &interface) const
+ {
+ return this->m_base.get().subtag(this->m_tag) == interface.device().tag();
+ }
+
/// \brief Find device
///
/// Find device of desired type with requested tag. If a device
diff --git a/src/emu/device.cpp b/src/emu/device.cpp
index a816067c535..aa4a7daa99d 100644
--- a/src/emu/device.cpp
+++ b/src/emu/device.cpp
@@ -215,8 +215,10 @@ std::string device_t::parameter(const char *tag) const
void device_t::add_machine_configuration(machine_config &config)
{
assert(&config == &m_machine_config);
- machine_config::token const token(config.begin_configuration(*this));
+ machine_config::token const tok(config.begin_configuration(*this));
device_add_mconfig(config);
+ for (finder_base *autodev = m_auto_finder_list; autodev != nullptr; autodev = autodev->next())
+ autodev->end_configuration();
}
@@ -493,8 +495,8 @@ bool device_t::findit(bool pre_map, bool isvalidation) const
if (isvalidation)
{
// sanity checking
- const char *tag = autodev->finder_tag();
- if (tag == nullptr)
+ char const *const tag = autodev->finder_tag();
+ if (!tag)
{
osd_printf_error("Finder tag is null!\n");
allfound = false;
diff --git a/src/emu/disound.cpp b/src/emu/disound.cpp
index f8931ae6d24..2e16107b996 100644
--- a/src/emu/disound.cpp
+++ b/src/emu/disound.cpp
@@ -22,9 +22,9 @@
//-------------------------------------------------
device_sound_interface::device_sound_interface(const machine_config &mconfig, device_t &device)
- : device_interface(device, "sound"),
- m_outputs(0),
- m_auto_allocated_inputs(0)
+ : device_interface(device, "sound")
+ , m_outputs(0)
+ , m_auto_allocated_inputs(0)
{
}
@@ -39,6 +39,29 @@ device_sound_interface::~device_sound_interface()
//-------------------------------------------------
+// add_route - send sound output to a consumer
+//-------------------------------------------------
+
+void device_sound_interface::add_route(u32 output, const char *target, double gain, u32 input, u32 mixoutput)
+{
+ assert(!device().started());
+ m_route_list.emplace_back(sound_route{ output, input, mixoutput, float(gain), device().mconfig().current_device(), target });
+}
+
+void device_sound_interface::add_route(u32 output, device_sound_interface &target, double gain, u32 input, u32 mixoutput)
+{
+ assert(!device().started());
+ m_route_list.emplace_back(sound_route{ output, input, mixoutput, float(gain), target.device(), DEVICE_SELF });
+}
+
+void device_sound_interface::add_route(u32 output, speaker_device &target, double gain, u32 input, u32 mixoutput)
+{
+ assert(!device().started());
+ m_route_list.emplace_back(sound_route{ output, input, mixoutput, float(gain), target, DEVICE_SELF });
+}
+
+
+//-------------------------------------------------
// stream_alloc - allocate a stream implicitly
// associated with this device
//-------------------------------------------------
@@ -202,17 +225,17 @@ int device_sound_interface::inputnum_from_device(device_t &source_device, int ou
void device_sound_interface::interface_validity_check(validity_checker &valid) const
{
// loop over all the routes
- for (auto &route : routes())
+ for (sound_route const &route : routes())
{
// find a device with the requested tag
- const device_t *target = device().siblingdevice(route->m_target.c_str());
- if (target == nullptr)
- osd_printf_error("Attempting to route sound to non-existent device '%s'\n", route->m_target.c_str());
+ device_t const *const target = route.m_base.get().subdevice(route.m_target.c_str());
+ if (!target)
+ osd_printf_error("Attempting to route sound to non-existent device '%s'\n", route.m_base.get().subtag(route.m_target.c_str()).c_str());
// if it's not a speaker or a sound device, error
- const device_sound_interface *sound;
- if (target != nullptr && target->type() != SPEAKER && !target->interface(sound))
- osd_printf_error("Attempting to route sound to a non-sound device '%s' (%s)\n", route->m_target.c_str(), target->name());
+ device_sound_interface const *sound;
+ if (target && (target->type() != SPEAKER) && !target->interface(sound))
+ osd_printf_error("Attempting to route sound to a non-sound device '%s' (%s)\n", target->tag(), target->name());
}
}
@@ -226,14 +249,14 @@ void device_sound_interface::interface_pre_start()
{
// scan all the sound devices
sound_interface_iterator iter(m_device.machine().root_device());
- for (device_sound_interface &sound : iter)
+ for (device_sound_interface const &sound : iter)
{
// scan each route on the device
- for (auto &route : sound.routes())
+ for (sound_route const &route : sound.routes())
{
// see if we are the target of this route; if we are, make sure the source device is started
- device_t *target_device = sound.device().siblingdevice(route->m_target.c_str());
- if (target_device == &m_device && !sound.device().started())
+ device_t *const target_device = route.m_base.get().subdevice(route.m_target.c_str());
+ if ((target_device == &m_device) && !sound.device().started())
throw device_missing_dependencies();
}
}
@@ -243,14 +266,14 @@ void device_sound_interface::interface_pre_start()
for (device_sound_interface &sound : iter)
{
// scan each route on the device
- for (auto &route : sound.routes())
+ for (sound_route &route : sound.routes())
{
// see if we are the target of this route
- device_t *target_device = sound.device().siblingdevice(route->m_target.c_str());
- if (target_device == &m_device && route->m_input == AUTO_ALLOC_INPUT)
+ device_t *const target_device = route.m_base.get().subdevice(route.m_target.c_str());
+ if ((target_device == &m_device) && (route.m_input == AUTO_ALLOC_INPUT))
{
- route->m_input = m_auto_allocated_inputs;
- m_auto_allocated_inputs += (route->m_output == ALL_OUTPUTS) ? sound.outputs() : 1;
+ route.m_input = m_auto_allocated_inputs;
+ m_auto_allocated_inputs += (route.m_output == ALL_OUTPUTS) ? sound.outputs() : 1;
}
}
}
@@ -268,32 +291,32 @@ void device_sound_interface::interface_post_start()
for (device_sound_interface &sound : sound_interface_iterator(m_device.machine().root_device()))
{
// scan each route on the device
- for (auto &route : sound.routes())
+ for (sound_route const &route : sound.routes())
{
// if we are the target of this route, hook it up
- device_t *target_device = sound.device().siblingdevice(route->m_target.c_str());
+ device_t *const target_device = route.m_base.get().subdevice(route.m_target.c_str());
if (target_device == &m_device)
{
// iterate over all outputs, matching any that apply
- int inputnum = route->m_input;
- int numoutputs = sound.outputs();
+ int inputnum = route.m_input;
+ int const numoutputs = sound.outputs();
for (int outputnum = 0; outputnum < numoutputs; outputnum++)
- if (route->m_output == outputnum || route->m_output == ALL_OUTPUTS)
+ if ((route.m_output == outputnum) || (route.m_output == ALL_OUTPUTS))
{
// find the output stream to connect from
int streamoutputnum;
- sound_stream *outputstream = sound.output_to_stream_output(outputnum, streamoutputnum);
- if (outputstream == nullptr)
- fatalerror("Sound device '%s' specifies route for non-existant output #%d\n", route->m_target.c_str(), outputnum);
+ sound_stream *const outputstream = sound.output_to_stream_output(outputnum, streamoutputnum);
+ if (!outputstream)
+ fatalerror("Sound device '%s' specifies route for non-existent output #%d\n", sound.device().tag(), outputnum);
// find the input stream to connect to
int streaminputnum;
- sound_stream *inputstream = input_to_stream_input(inputnum++, streaminputnum);
- if (inputstream == nullptr)
- fatalerror("Sound device '%s' targeted output #%d to non-existant device '%s' input %d\n", route->m_target.c_str(), outputnum, m_device.tag(), inputnum - 1);
+ sound_stream *const inputstream = input_to_stream_input(inputnum++, streaminputnum);
+ if (!inputstream)
+ fatalerror("Sound device '%s' targeted output #%d to non-existant device '%s' input %d\n", sound.device().tag(), outputnum, m_device.tag(), inputnum - 1);
// set the input
- inputstream->set_input(streaminputnum, outputstream, streamoutputnum, route->m_gain);
+ inputstream->set_input(streaminputnum, outputstream, streamoutputnum, route.m_gain);
}
}
}
@@ -317,25 +340,6 @@ void device_sound_interface::interface_pre_reset()
//**************************************************************************
-// SOUND ROUTE
-//**************************************************************************
-
-//-------------------------------------------------
-// sound_route - constructor
-//-------------------------------------------------
-
-device_sound_interface::sound_route::sound_route(int output, int input, float gain, const char *target, u32 mixoutput)
- : m_output(output),
- m_input(input),
- m_mixoutput(mixoutput),
- m_gain(gain),
- m_target(target)
-{
-}
-
-
-
-//**************************************************************************
// SIMPLE DERIVED MIXER INTERFACE
//**************************************************************************
@@ -381,18 +385,20 @@ void device_mixer_interface::interface_pre_start()
m_outputmap.resize(m_auto_allocated_inputs);
// iterate through all routes that point to us and note their mixer output
- for (device_sound_interface &sound : sound_interface_iterator(m_device.machine().root_device()))
- for (auto &route : sound.routes())
+ for (device_sound_interface const &sound : sound_interface_iterator(m_device.machine().root_device()))
+ {
+ for (sound_route const &route : sound.routes())
{
// see if we are the target of this route
- device_t *target_device = sound.device().siblingdevice(route->m_target.c_str());
- if (target_device == &device() && route->m_input < m_auto_allocated_inputs)
+ device_t *const target_device = route.m_base.get().subdevice(route.m_target.c_str());
+ if ((target_device == &device()) && (route.m_input < m_auto_allocated_inputs))
{
- int count = (route->m_output == ALL_OUTPUTS) ? sound.outputs() : 1;
+ int const count = (route.m_output == ALL_OUTPUTS) ? sound.outputs() : 1;
for (int output = 0; output < count; output++)
- m_outputmap[route->m_input + output] = route->m_mixoutput;
+ m_outputmap[route.m_input + output] = route.m_mixoutput;
}
}
+ }
// allocate the mixer stream
m_mixer_stream = stream_alloc(m_auto_allocated_inputs, m_outputs, device().machine().sample_rate());
diff --git a/src/emu/disound.h b/src/emu/disound.h
index 7c57b12b9bc..da968abd789 100644
--- a/src/emu/disound.h
+++ b/src/emu/disound.h
@@ -17,6 +17,8 @@
#ifndef MAME_EMU_DISOUND_H
#define MAME_EMU_DISOUND_H
+#include <functional>
+
//**************************************************************************
// CONSTANTS
@@ -66,13 +68,12 @@ public:
class sound_route
{
public:
- sound_route(int output, int input, float gain, const char *target, u32 mixoutput);
-
- u32 m_output; // output index, or ALL_OUTPUTS
- u32 m_input; // target input index
- u32 m_mixoutput; // target mixer output
- float m_gain; // gain
- std::string m_target; // target tag
+ u32 m_output; // output index, or ALL_OUTPUTS
+ u32 m_input; // target input index
+ u32 m_mixoutput; // target mixer output
+ float m_gain; // gain
+ std::reference_wrapper<device_t> m_base; // target search base
+ std::string m_target; // target tag
};
// construction/destruction
@@ -82,13 +83,12 @@ public:
virtual bool issound() { return true; } /// HACK: allow devices to hide from the ui
// configuration access
- const std::vector<std::unique_ptr<sound_route>> &routes() const { return m_route_list; }
+ std::vector<sound_route> const &routes() const { return m_route_list; }
- // inline configuration helpers
- void add_route(u32 output, const char *target, double gain, u32 input = AUTO_ALLOC_INPUT, u32 mixoutput = 0)
- {
- m_route_list.push_back(std::make_unique<sound_route>(output, input, gain, target, mixoutput));
- }
+ // configuration helpers
+ void add_route(u32 output, const char *target, double gain, u32 input = AUTO_ALLOC_INPUT, u32 mixoutput = 0);
+ void add_route(u32 output, device_sound_interface &target, double gain, u32 input = AUTO_ALLOC_INPUT, u32 mixoutput = 0);
+ void add_route(u32 output, speaker_device &target, double gain, u32 input = AUTO_ALLOC_INPUT, u32 mixoutput = 0);
void reset_routes() { m_route_list.clear(); }
// sound stream update overrides
@@ -107,6 +107,9 @@ public:
int inputnum_from_device(device_t &device, int outputnum = 0) const;
protected:
+ // configuration access
+ std::vector<sound_route> &routes() { return m_route_list; }
+
// optional operation overrides
virtual void interface_validity_check(validity_checker &valid) const override;
virtual void interface_pre_start() override;
@@ -114,7 +117,7 @@ protected:
virtual void interface_pre_reset() override;
// internal state
- std::vector<std::unique_ptr<sound_route>> m_route_list; // list of sound routes
+ std::vector<sound_route> m_route_list; // list of sound routes
int m_outputs; // number of outputs from this instance
int m_auto_allocated_inputs; // number of auto-allocated inputs targeting us
};
diff --git a/src/emu/emufwd.h b/src/emu/emufwd.h
index 20330d3c84d..f5de6232f05 100644
--- a/src/emu/emufwd.h
+++ b/src/emu/emufwd.h
@@ -225,6 +225,9 @@ class software_list_loader;
class sound_manager;
class sound_stream;
+// declared in speaker.h
+class speaker_device;
+
// declared in tilemap.h
class tilemap_device;
class tilemap_manager;