From 688d6e212814ad041c2d382020bf320c2dafabbf Mon Sep 17 00:00:00 2001 From: hap Date: Sat, 9 Sep 2023 21:19:24 +0200 Subject: sound: add configurable speaker panning --- src/emu/sound.cpp | 51 ++++++++++++++++++---- src/emu/speaker.cpp | 62 ++++++++++++++++++++------ src/emu/speaker.h | 13 ++++-- src/frontend/mame/ui/ui.cpp | 101 ++++++++++++++++++++++++++++++------------- src/frontend/mame/ui/ui.h | 1 + src/mame/midway/williams.cpp | 4 -- 6 files changed, 172 insertions(+), 60 deletions(-) diff --git a/src/emu/sound.cpp b/src/emu/sound.cpp index 45f430e2461..967a012e20e 100644 --- a/src/emu/sound.cpp +++ b/src/emu/sound.cpp @@ -1385,17 +1385,35 @@ void sound_manager::config_load(config_type cfg_type, config_level cfg_level, ut } // iterate over channel nodes - for (util::xml::data_node const *channelnode = parentnode->get_child("channel"); channelnode != nullptr; channelnode = channelnode->get_next_sibling("channel")) + for (util::xml::data_node const *node = parentnode->get_child("channel"); node != nullptr; node = node->get_next_sibling("channel")) { mixer_input info; - if (indexed_mixer_input(channelnode->get_attribute_int("index", -1), info)) + if (indexed_mixer_input(node->get_attribute_int("index", -1), info)) { - float defvol = channelnode->get_attribute_float("defvol", 1.0f); - float newvol = channelnode->get_attribute_float("newvol", -1000.0f); + float defvol = node->get_attribute_float("defvol", 1.0f); + float newvol = node->get_attribute_float("newvol", -1000.0f); if (newvol != -1000.0f) info.stream->input(info.inputnum).set_user_gain(newvol / defvol); } } + + // iterate over speaker panning nodes + for (util::xml::data_node const *node = parentnode->get_child("panning"); node != nullptr; node = node->get_next_sibling("panning")) + { + char const *const tag = node->get_attribute_string("tag", nullptr); + if (tag != nullptr) + { + for (speaker_device &speaker : speaker_device_enumerator(machine().root_device())) + { + if (!strcmp(tag, speaker.tag())) + { + float value = node->get_attribute_float("value", speaker.defpan()); + speaker.set_pan(value); + break; + } + } + } + } } @@ -1417,7 +1435,7 @@ void sound_manager::config_save(config_type cfg_type, util::xml::data_node *pare node->set_attribute_int("value", m_attenuation); } - // iterate over mixer channels + // iterate over mixer channels for per-channel volume for (int mixernum = 0; ; mixernum++) { mixer_input info; @@ -1427,11 +1445,26 @@ void sound_manager::config_save(config_type cfg_type, util::xml::data_node *pare float const newvol = info.stream->input(info.inputnum).user_gain(); if (newvol != 1.0f) { - util::xml::data_node *const channelnode = parentnode->add_child("channel", nullptr); - if (channelnode) + util::xml::data_node *const node = parentnode->add_child("channel", nullptr); + if (node) + { + node->set_attribute_int("index", mixernum); + node->set_attribute_float("newvol", newvol); + } + } + } + + // iterate over speakers for panning + for (speaker_device &speaker : speaker_device_enumerator(machine().root_device())) + { + float value = speaker.pan(); + if (value != speaker.defpan()) + { + util::xml::data_node *const node = parentnode->add_child("panning", nullptr); + if (node) { - channelnode->set_attribute_int("index", mixernum); - channelnode->set_attribute_float("newvol", newvol); + node->set_attribute("tag", speaker.tag()); + node->set_attribute_float("value", value); } } } diff --git a/src/emu/speaker.cpp b/src/emu/speaker.cpp index 3cbb14355a4..0755aab5af3 100644 --- a/src/emu/speaker.cpp +++ b/src/emu/speaker.cpp @@ -37,6 +37,8 @@ speaker_device::speaker_device(const machine_config &mconfig, const char *tag, d , m_x(0.0) , m_y(0.0) , m_z(0.0) + , m_pan(1.0) + , m_defpan(1.0) , m_current_max(0) , m_samples_this_bucket(0) { @@ -52,6 +54,35 @@ speaker_device::~speaker_device() } +//------------------------------------------------- +// set_position - set speaker position +//------------------------------------------------- + +speaker_device &speaker_device::set_position(double x, double y, double z) +{ + // as mentioned in the header file, y and z params currently have no effect + m_x = x; + m_y = y; + m_z = z; + + // hard pan to left + if (m_x < 0.0) + set_pan(0.0f); + + // hard pan to right + else if (m_x > 0.0) + set_pan(2.0f); + + // center (mono) + else + set_pan(1.0f); + + m_defpan = m_pan; + + return *this; +} + + //------------------------------------------------- // mix - mix in samples from the speaker's stream //------------------------------------------------- @@ -89,24 +120,29 @@ void speaker_device::mix(stream_buffer::sample_t *leftmix, stream_buffer::sample // mix if sound is enabled if (!suppress) { - // if the speaker is centered, send to both left and right - if (m_x == 0) + // if the speaker is hard panned to the left, send only to the left + if (m_pan == 0.0f) for (int sample = 0; sample < expected_samples; sample++) - { - stream_buffer::sample_t cursample = view.get(sample); - leftmix[sample] += cursample; - rightmix[sample] += cursample; - } + leftmix[sample] += view.get(sample); - // if the speaker is to the left, send only to the left - else if (m_x < 0) + // if the speaker is hard panned to the right, send only to the right + else if (m_pan == 2.0f) for (int sample = 0; sample < expected_samples; sample++) - leftmix[sample] += view.get(sample); + rightmix[sample] += view.get(sample); - // if the speaker is to the right, send only to the right + // otherwise, send to both else + { + const float leftpan = (m_pan <= 1.0f) ? 1.0f : 2.0f - m_pan; + const float rightpan = (m_pan >= 1.0f) ? 1.0f : m_pan; + for (int sample = 0; sample < expected_samples; sample++) - rightmix[sample] += view.get(sample); + { + stream_buffer::sample_t cursample = view.get(sample); + leftmix[sample] += cursample * leftpan; + rightmix[sample] += cursample * rightpan; + } + } } } @@ -117,7 +153,6 @@ void speaker_device::mix(stream_buffer::sample_t *leftmix, stream_buffer::sample void speaker_device::device_start() { - // dummy save to make device.c happy } @@ -187,4 +222,3 @@ void speaker_device::device_stop() } } } - diff --git a/src/emu/speaker.h b/src/emu/speaker.h index 54aa00603c9..b55554d6164 100644 --- a/src/emu/speaker.h +++ b/src/emu/speaker.h @@ -53,8 +53,8 @@ public: speaker_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0); virtual ~speaker_device(); - // inline configuration helpers - speaker_device &set_position(double x, double y, double z) { m_x = x; m_y = y; m_z = z; return *this; } + // configuration helpers + speaker_device &set_position(double x, double y, double z); speaker_device &front_center() { set_position( 0.0, 0.0, 1.0); return *this; } speaker_device &front_left() { set_position(-0.2, 0.0, 1.0); return *this; } speaker_device &front_floor() { set_position( 0.0, -0.5, 1.0); return *this; } @@ -71,15 +71,22 @@ public: // internally for use by the sound system void mix(stream_buffer::sample_t *leftmix, stream_buffer::sample_t *rightmix, attotime start, attotime end, int expected_samples, bool suppress); + // panning + void set_pan(double pan) { m_pan = std::clamp(pan, 0.0, 2.0); } + float pan() { return m_pan; } + float defpan() { return m_defpan; } + protected: // device-level overrides virtual void device_start() override ATTR_COLD; virtual void device_stop() override ATTR_COLD; - // inline configuration state + // configuration state double m_x; double m_y; double m_z; + float m_pan; + float m_defpan; // internal state static constexpr int BUCKETS_PER_SECOND = 10; diff --git a/src/frontend/mame/ui/ui.cpp b/src/frontend/mame/ui/ui.cpp index b839e363195..e8022d112de 100644 --- a/src/frontend/mame/ui/ui.cpp +++ b/src/frontend/mame/ui/ui.cpp @@ -40,6 +40,7 @@ #include "rendfont.h" #include "romload.h" #include "screen.h" +#include "speaker.h" #include "uiinput.h" // FIXME: allow OSD module headers to be included in a less ugly way @@ -1477,11 +1478,15 @@ std::vector mame_ui_manager::slider_init(running_machine &machine mixer_input info; for (int item = 0; machine.sound().indexed_mixer_input(item, info); item++) { - int32_t maxval = 2000; - int32_t defval = 1000; - std::string str = string_format(_("%1$s Volume"), info.stream->input(info.inputnum).name()); - slider_alloc(std::move(str), 0, defval, maxval, 20, std::bind(&mame_ui_manager::slider_mixervol, this, item, _1, _2)); + slider_alloc(std::move(str), 0, 1000, 2000, 20, std::bind(&mame_ui_manager::slider_mixervol, this, item, _1, _2)); + } + + // add speaker panning + for (speaker_device &speaker : speaker_device_enumerator(machine.root_device())) + { + std::string str = string_format(_("%s '%s' Panning"), speaker.name(), speaker.tag()); + slider_alloc(std::move(str), 0, floor(speaker.defpan() * 1000.0 + 0.5), 2000, 20, std::bind(&mame_ui_manager::slider_panning, this, std::ref(speaker), _1, _2)); } // add analog adjusters @@ -1491,8 +1496,7 @@ std::vector mame_ui_manager::slider_init(running_machine &machine { if (field.type() == IPT_ADJUSTER) { - slider_alloc(field.name(), field.minval(), field.defvalue(), field.maxval(), 1, - std::bind(&mame_ui_manager::slider_adjuster, this, std::ref(field), _1, _2)); + slider_alloc(field.name(), field.minval(), field.defvalue(), field.maxval(), 1, std::bind(&mame_ui_manager::slider_adjuster, this, std::ref(field), _1, _2)); } } } @@ -1565,13 +1569,11 @@ std::vector mame_ui_manager::slider_init(running_machine &machine // add scale and offset controls per-overlay std::string str = string_format(_("Laserdisc '%1$s' Horiz Stretch"), laserdisc.tag()); - slider_alloc(std::move(str), 500, (defxscale == 0) ? 1000 : defxscale, 1500, 2, - std::bind(&mame_ui_manager::slider_overxscale, this, std::ref(laserdisc), _1, _2)); + slider_alloc(std::move(str), 500, (defxscale == 0) ? 1000 : defxscale, 1500, 2, std::bind(&mame_ui_manager::slider_overxscale, this, std::ref(laserdisc), _1, _2)); str = string_format(_("Laserdisc '%1$s' Horiz Position"), laserdisc.tag()); slider_alloc(std::move(str), -500, defxoffset, 500, 2, std::bind(&mame_ui_manager::slider_overxoffset, this, std::ref(laserdisc), _1, _2)); str = string_format(_("Laserdisc '%1$s' Vert Stretch"), laserdisc.tag()); - slider_alloc(std::move(str), 500, (defyscale == 0) ? 1000 : defyscale, 1500, 2, - std::bind(&mame_ui_manager::slider_overyscale, this, std::ref(laserdisc), _1, _2)); + slider_alloc(std::move(str), 500, (defyscale == 0) ? 1000 : defyscale, 1500, 2, std::bind(&mame_ui_manager::slider_overyscale, this, std::ref(laserdisc), _1, _2)); str = string_format(_("Laserdisc '%1$s' Vert Position"), laserdisc.tag()); slider_alloc(std::move(str), -500, defyoffset, 500, 2, std::bind(&mame_ui_manager::slider_overyoffset, this, std::ref(laserdisc), _1, _2)); } @@ -1648,14 +1650,53 @@ int32_t mame_ui_manager::slider_mixervol(int item, std::string *str, int32_t new { int32_t curval = floor(info.stream->input(info.inputnum).user_gain() * 1000.0f + 0.5f); if (newval > curval && (newval - curval) <= 4) newval += 4; // round up on increment - info.stream->input(info.inputnum).set_user_gain((float)newval * 0.001f); + info.stream->input(info.inputnum).set_user_gain(float(newval) * 0.001f); } if (str) - *str = string_format("%4.2f", info.stream->input(info.inputnum).user_gain()); + *str = string_format("%1.2f", info.stream->input(info.inputnum).user_gain()); return floorf(info.stream->input(info.inputnum).user_gain() * 1000.0f + 0.5f); } +//------------------------------------------------- +// slider_panning - speaker panning slider +// callback +//------------------------------------------------- + +int32_t mame_ui_manager::slider_panning(speaker_device &speaker, std::string *str, int32_t newval) +{ + if (newval != SLIDER_NOCHANGE) + speaker.set_pan(float(newval) * 0.001f); + + int32_t curval = floor(speaker.pan() * 1000.0f + 0.5f); + if (str) + { + switch (curval) + { + // preset strings for exact center/left/right + case 1000: + *str = _("Center"); + break; + + case 0: + *str = _("Left"); + break; + + case 2000: + *str = _("Right"); + break; + + // otherwise show as floating point + default: + *str = string_format("%1.2f", float(curval) * 0.001f); + break; + } + } + + return curval; +} + + //------------------------------------------------- // slider_adjuster - analog adjuster slider // callback @@ -1685,7 +1726,7 @@ int32_t mame_ui_manager::slider_adjuster(ioport_field &field, std::string *str, int32_t mame_ui_manager::slider_overclock(device_t &device, std::string *str, int32_t newval) { if (newval != SLIDER_NOCHANGE) - device.set_clock_scale((float)newval * 0.001f); + device.set_clock_scale(float(newval) * 0.001f); if (str) *str = string_format(_("%1$3.0f%%"), floor(device.clock_scale() * 100.0 + 0.5)); return floor(device.clock_scale() * 1000.0 + 0.5); @@ -1706,7 +1747,7 @@ int32_t mame_ui_manager::slider_refresh(screen_device &screen, std::string *str, int width = screen.width(); int height = screen.height(); const rectangle &visarea = screen.visible_area(); - screen.configure(width, height, visarea, HZ_TO_ATTOSECONDS(defrefresh + (double)newval * 0.001)); + screen.configure(width, height, visarea, HZ_TO_ATTOSECONDS(defrefresh + double(newval) * 0.001)); } if (str) @@ -1726,7 +1767,7 @@ int32_t mame_ui_manager::slider_brightness(screen_device &screen, std::string *s render_container::user_settings settings = screen.container().get_user_settings(); if (newval != SLIDER_NOCHANGE) { - settings.m_brightness = (float)newval * 0.001f; + settings.m_brightness = float(newval) * 0.001f; screen.container().set_user_settings(settings); } if (str) @@ -1745,7 +1786,7 @@ int32_t mame_ui_manager::slider_contrast(screen_device &screen, std::string *str render_container::user_settings settings = screen.container().get_user_settings(); if (newval != SLIDER_NOCHANGE) { - settings.m_contrast = (float)newval * 0.001f; + settings.m_contrast = float(newval) * 0.001f; screen.container().set_user_settings(settings); } if (str) @@ -1763,7 +1804,7 @@ int32_t mame_ui_manager::slider_gamma(screen_device &screen, std::string *str, i render_container::user_settings settings = screen.container().get_user_settings(); if (newval != SLIDER_NOCHANGE) { - settings.m_gamma = (float)newval * 0.001f; + settings.m_gamma = float(newval) * 0.001f; screen.container().set_user_settings(settings); } if (str) @@ -1782,7 +1823,7 @@ int32_t mame_ui_manager::slider_xscale(screen_device &screen, std::string *str, render_container::user_settings settings = screen.container().get_user_settings(); if (newval != SLIDER_NOCHANGE) { - settings.m_xscale = (float)newval * 0.001f; + settings.m_xscale = float(newval) * 0.001f; screen.container().set_user_settings(settings); } if (str) @@ -1801,7 +1842,7 @@ int32_t mame_ui_manager::slider_yscale(screen_device &screen, std::string *str, render_container::user_settings settings = screen.container().get_user_settings(); if (newval != SLIDER_NOCHANGE) { - settings.m_yscale = (float)newval * 0.001f; + settings.m_yscale = float(newval) * 0.001f; screen.container().set_user_settings(settings); } if (str) @@ -1820,7 +1861,7 @@ int32_t mame_ui_manager::slider_xoffset(screen_device &screen, std::string *str, render_container::user_settings settings = screen.container().get_user_settings(); if (newval != SLIDER_NOCHANGE) { - settings.m_xoffset = (float)newval * 0.001f; + settings.m_xoffset = float(newval) * 0.001f; screen.container().set_user_settings(settings); } if (str) @@ -1839,7 +1880,7 @@ int32_t mame_ui_manager::slider_yoffset(screen_device &screen, std::string *str, render_container::user_settings settings = screen.container().get_user_settings(); if (newval != SLIDER_NOCHANGE) { - settings.m_yoffset = (float)newval * 0.001f; + settings.m_yoffset = float(newval) * 0.001f; screen.container().set_user_settings(settings); } if (str) @@ -1860,7 +1901,7 @@ int32_t mame_ui_manager::slider_overxscale(laserdisc_device &laserdisc, std::str laserdisc.get_overlay_config(settings); if (newval != SLIDER_NOCHANGE) { - settings.m_overscalex = (float)newval * 0.001f; + settings.m_overscalex = float(newval) * 0.001f; laserdisc.set_overlay_config(settings); } if (str) @@ -1881,7 +1922,7 @@ int32_t mame_ui_manager::slider_overyscale(laserdisc_device &laserdisc, std::str laserdisc.get_overlay_config(settings); if (newval != SLIDER_NOCHANGE) { - settings.m_overscaley = (float)newval * 0.001f; + settings.m_overscaley = float(newval) * 0.001f; laserdisc.set_overlay_config(settings); } if (str) @@ -1902,7 +1943,7 @@ int32_t mame_ui_manager::slider_overxoffset(laserdisc_device &laserdisc, std::st laserdisc.get_overlay_config(settings); if (newval != SLIDER_NOCHANGE) { - settings.m_overposx = (float)newval * 0.001f; + settings.m_overposx = float(newval) * 0.001f; laserdisc.set_overlay_config(settings); } if (str) @@ -1923,7 +1964,7 @@ int32_t mame_ui_manager::slider_overyoffset(laserdisc_device &laserdisc, std::st laserdisc.get_overlay_config(settings); if (newval != SLIDER_NOCHANGE) { - settings.m_overposy = (float)newval * 0.001f; + settings.m_overposy = float(newval) * 0.001f; laserdisc.set_overlay_config(settings); } if (str) @@ -1940,7 +1981,7 @@ int32_t mame_ui_manager::slider_overyoffset(laserdisc_device &laserdisc, std::st int32_t mame_ui_manager::slider_flicker([[maybe_unused]] screen_device &screen, std::string *str, int32_t newval) { if (newval != SLIDER_NOCHANGE) - vector_options::s_flicker = (float)newval * 0.001f; + vector_options::s_flicker = float(newval) * 0.001f; if (str) *str = string_format(_("%1$1.2f"), vector_options::s_flicker); return floor(vector_options::s_flicker * 1000.0f + 0.5f); @@ -1955,7 +1996,7 @@ int32_t mame_ui_manager::slider_flicker([[maybe_unused]] screen_device &screen, int32_t mame_ui_manager::slider_beam_width_min([[maybe_unused]] screen_device &screen, std::string *str, int32_t newval) { if (newval != SLIDER_NOCHANGE) - vector_options::s_beam_width_min = std::min((float)newval * 0.01f, vector_options::s_beam_width_max); + vector_options::s_beam_width_min = std::min(float(newval) * 0.01f, vector_options::s_beam_width_max); if (str != nullptr) *str = string_format(_("%1$1.2f"), vector_options::s_beam_width_min); return floor(vector_options::s_beam_width_min * 100.0f + 0.5f); @@ -1970,7 +2011,7 @@ int32_t mame_ui_manager::slider_beam_width_min([[maybe_unused]] screen_device &s int32_t mame_ui_manager::slider_beam_width_max([[maybe_unused]] screen_device &screen, std::string *str, int32_t newval) { if (newval != SLIDER_NOCHANGE) - vector_options::s_beam_width_max = std::max((float)newval * 0.01f, vector_options::s_beam_width_min); + vector_options::s_beam_width_max = std::max(float(newval) * 0.01f, vector_options::s_beam_width_min); if (str != nullptr) *str = string_format(_("%1$1.2f"), vector_options::s_beam_width_max); return floor(vector_options::s_beam_width_max * 100.0f + 0.5f); @@ -1985,7 +2026,7 @@ int32_t mame_ui_manager::slider_beam_width_max([[maybe_unused]] screen_device &s int32_t mame_ui_manager::slider_beam_dot_size([[maybe_unused]] screen_device &screen, std::string *str, int32_t newval) { if (newval != SLIDER_NOCHANGE) - vector_options::s_beam_dot_size = std::max((float)newval * 0.01f, 0.1f); + vector_options::s_beam_dot_size = std::max(float(newval) * 0.01f, 0.1f); if (str != nullptr) *str = string_format(_("%1$1.2f"), vector_options::s_beam_dot_size); return floor(vector_options::s_beam_dot_size * 100.0f + 0.5f); @@ -2000,7 +2041,7 @@ int32_t mame_ui_manager::slider_beam_dot_size([[maybe_unused]] screen_device &sc int32_t mame_ui_manager::slider_beam_intensity_weight([[maybe_unused]] screen_device &screen, std::string *str, int32_t newval) { if (newval != SLIDER_NOCHANGE) - vector_options::s_beam_intensity_weight = (float)newval * 0.001f; + vector_options::s_beam_intensity_weight = float(newval) * 0.001f; if (str != nullptr) *str = string_format(_("%1$1.2f"), vector_options::s_beam_intensity_weight); return floor(vector_options::s_beam_intensity_weight * 1000.0f + 0.5f); diff --git a/src/frontend/mame/ui/ui.h b/src/frontend/mame/ui/ui.h index ebf0f74760e..662d8d06fc1 100644 --- a/src/frontend/mame/ui/ui.h +++ b/src/frontend/mame/ui/ui.h @@ -288,6 +288,7 @@ private: // slider controls int32_t slider_volume(std::string *str, int32_t newval); int32_t slider_mixervol(int item, std::string *str, int32_t newval); + int32_t slider_panning(speaker_device &speaker, std::string *str, int32_t newval); int32_t slider_adjuster(ioport_field &field, std::string *str, int32_t newval); int32_t slider_overclock(device_t &device, std::string *str, int32_t newval); int32_t slider_refresh(screen_device &screen, std::string *str, int32_t newval); diff --git a/src/mame/midway/williams.cpp b/src/mame/midway/williams.cpp index f72073105b4..506c0b69181 100644 --- a/src/mame/midway/williams.cpp +++ b/src/mame/midway/williams.cpp @@ -1707,10 +1707,6 @@ void sinistar_state::cockpit(machine_config &config) SPEAKER(config, "rspeaker").rear_center(); MC1408(config, "rdac").add_route(ALL_OUTPUTS, "rspeaker", 0.25); // unknown DAC - // uncomment this to route front/rear to left/right - //subdevice("speaker")->front_left(); - //subdevice("rspeaker")->front_right(); - // pia INPUT_MERGER_ANY_HIGH(config, "soundirq_b").output_handler().set_inputline("soundcpu_b", M6808_IRQ_LINE); -- cgit v1.2.3