summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2021-05-31 11:20:28 -0700
committer Aaron Giles <aaron@aarongiles.com>2021-05-31 11:20:28 -0700
commit05cacea947d7db129c25f33c85aca7ec74be6799 (patch)
tree1211caac4a3428254f73596af8c61b0b6fe9f9b1
parentb1e775504bb02c1168d64853ca058cbcce6b5978 (diff)
ympsr60: Fleshed out the PSR60/PSR70 drivers
* Split YM2154 into a separate device * Created fake YM2154 ROMs as placeholders * Created new BBD sound device in src/devices/sound/bbd.cpp * Created new mixer device in src/devices/sound/mixer.cpp * Connected YM2154 and BBD devices * Approximated BBD driver behavior * Exposed analog sliders as adjusters (accessible via ` menu) * Added sliders to layout and animated them
-rw-r--r--scripts/src/sound.lua12
-rw-r--r--scripts/target/mame/mess.lua1
-rw-r--r--scripts/target/mame/virtual.lua1
-rw-r--r--src/devices/sound/bbd.cpp118
-rw-r--r--src/devices/sound/bbd.h81
-rw-r--r--src/devices/sound/mixer.cpp30
-rw-r--r--src/devices/sound/mixer.h27
-rw-r--r--src/devices/sound/ym2154.cpp311
-rw-r--r--src/devices/sound/ym2154.h99
-rw-r--r--src/mame/drivers/ympsr60.cpp266
-rw-r--r--src/mame/layout/psr60.lay91
-rw-r--r--src/mame/layout/psr70.lay63
12 files changed, 947 insertions, 153 deletions
diff --git a/scripts/src/sound.lua b/scripts/src/sound.lua
index 6de550d5dde..f9710d96547 100644
--- a/scripts/src/sound.lua
+++ b/scripts/src/sound.lua
@@ -10,12 +10,16 @@
----------------------------------------------------------------------------
files {
+ MAME_DIR .. "src/devices/sound/bbd.cpp",
+ MAME_DIR .. "src/devices/sound/bbd.h",
MAME_DIR .. "src/devices/sound/flt_biquad.cpp",
MAME_DIR .. "src/devices/sound/flt_biquad.h",
MAME_DIR .. "src/devices/sound/flt_vol.cpp",
MAME_DIR .. "src/devices/sound/flt_vol.h",
MAME_DIR .. "src/devices/sound/flt_rc.cpp",
MAME_DIR .. "src/devices/sound/flt_rc.h",
+ MAME_DIR .. "src/devices/sound/mixer.cpp",
+ MAME_DIR .. "src/devices/sound/mixer.h",
MAME_DIR .. "src/devices/sound/samples.cpp",
MAME_DIR .. "src/devices/sound/samples.h",
}
@@ -1169,6 +1173,7 @@ end
---------------------------------------------------
-- Yamaha FM synthesizers
+--@src/devices/sound/ym2154.h,SOUNDS["YM2154"] = true
--@src/devices/sound/ymopm.h,SOUNDS["YM2151"] = true
--@src/devices/sound/ymopz.h,SOUNDS["YM2414"] = true
--@src/devices/sound/ymopq.h,SOUNDS["YM3806"] = true
@@ -1185,6 +1190,13 @@ end
--@src/devices/sound/ymopl.h,SOUNDS["Y8950"] = true
---------------------------------------------------
+if (SOUNDS["YM2154"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/sound/ym2154.cpp",
+ MAME_DIR .. "src/devices/sound/ym2154.h",
+ }
+end
+
if (SOUNDS["YM2151"]~=null or SOUNDS["YM2164"]~=null) then
files {
MAME_DIR .. "src/devices/sound/ymopm.cpp",
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index 52dc912def7..84cd754592c 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -183,6 +183,7 @@ SOUNDS["SPEAKER"] = true
SOUNDS["BEEP"] = true
SOUNDS["DISCRETE"] = true
SOUNDS["AY8910"] = true
+SOUNDS["YM2154"] = true
SOUNDS["YM2151"] = true
SOUNDS["YM2414"] = true
SOUNDS["YM3806"] = true
diff --git a/scripts/target/mame/virtual.lua b/scripts/target/mame/virtual.lua
index e3d4da3a59d..6bd3c77cc80 100644
--- a/scripts/target/mame/virtual.lua
+++ b/scripts/target/mame/virtual.lua
@@ -56,6 +56,7 @@ SOUNDS["VGMVIZ"] = true
SOUNDS["WAVE"] = true
SOUNDS["X1_010"] = true
SOUNDS["Y8950"] = true
+SOUNDS["YM2154"] = true
SOUNDS["YM2151"] = true
SOUNDS["YM2414"] = true
SOUNDS["YM3806"] = true
diff --git a/src/devices/sound/bbd.cpp b/src/devices/sound/bbd.cpp
new file mode 100644
index 00000000000..d19a56d9084
--- /dev/null
+++ b/src/devices/sound/bbd.cpp
@@ -0,0 +1,118 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+#include "emu.h"
+#include "bbd.h"
+
+
+//**************************************************************************
+// BBD DEVICE BASE
+//**************************************************************************
+
+//-------------------------------------------------
+// bbd_device_base - constructor
+//-------------------------------------------------
+
+template<int Entries, int Outputs>
+bbd_device_base<Entries, Outputs>::bbd_device_base(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, device_type type) :
+ device_t(mconfig, type, tag, owner, clock),
+ device_sound_interface(mconfig, *this),
+ m_stream(nullptr),
+ m_curpos(0)
+{
+ std::fill_n(&m_buffer[0], Entries, 0);
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+template<int Entries, int Outputs>
+void bbd_device_base<Entries, Outputs>::device_start()
+{
+ m_stream = stream_alloc(1, Outputs, sample_rate());
+ save_item(NAME(m_buffer));
+}
+
+
+//-------------------------------------------------
+// device_clock_changed - handle a clock change
+//-------------------------------------------------
+
+template<int Entries, int Outputs>
+void bbd_device_base<Entries, Outputs>::device_clock_changed()
+{
+ m_stream->set_sample_rate(sample_rate());
+}
+
+
+//-------------------------------------------------
+// sound_stream_update - handle a stream update
+//-------------------------------------------------
+
+template<int Entries, int Outputs>
+void bbd_device_base<Entries, Outputs>::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
+{
+ // BBDs that I've seen so far typically have 2 outputs, with the first outputting
+ // sample n-1 and the second outputting sampe n; if chips with more outputs
+ // or other taps turn up, this logic will need to be made more flexible
+ for (int sampindex = 0; sampindex < outputs[0].samples(); sampindex++)
+ {
+ for (int outnum = 0; outnum < Outputs; outnum++)
+ outputs[outnum].put(sampindex, m_buffer[(m_curpos + (Outputs - 1) - outnum) % Entries]);
+ m_buffer[m_curpos] = inputs[0].get(sampindex);
+ m_curpos = (m_curpos + 1) % Entries;
+ }
+}
+
+
+//**************************************************************************
+// MN3004
+//**************************************************************************
+
+// device type definition
+DEFINE_DEVICE_TYPE(MN3004, mn3004_device, "mn3004", "MN3004 BBD")
+
+mn3004_device::mn3004_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ bbd_device_base(mconfig, tag, owner, clock, MN3004)
+{
+}
+
+
+//**************************************************************************
+// MN3005
+//**************************************************************************
+
+// device type definition
+DEFINE_DEVICE_TYPE(MN3005, mn3005_device, "mn3005", "MN3005 BBD")
+
+mn3005_device::mn3005_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ bbd_device_base(mconfig, tag, owner, clock, MN3005)
+{
+}
+
+
+//**************************************************************************
+// MN3006
+//**************************************************************************
+
+// device type definition
+DEFINE_DEVICE_TYPE(MN3006, mn3006_device, "mn3006", "MN3006 BBD")
+
+mn3006_device::mn3006_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ bbd_device_base(mconfig, tag, owner, clock, MN3006)
+{
+}
+
+
+//**************************************************************************
+// MN3204P
+//**************************************************************************
+
+// device type definition
+DEFINE_DEVICE_TYPE(MN3204P, mn3204p_device, "mn3204p", "MN3204P BBD")
+
+mn3204p_device::mn3204p_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ bbd_device_base(mconfig, tag, owner, clock, MN3204P)
+{
+}
diff --git a/src/devices/sound/bbd.h b/src/devices/sound/bbd.h
new file mode 100644
index 00000000000..799fae790c1
--- /dev/null
+++ b/src/devices/sound/bbd.h
@@ -0,0 +1,81 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+#ifndef MAME_SOUND_BBD_H
+#define MAME_SOUND_BBD_H
+
+#pragma once
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> bbd_device_base
+
+template<int Entries, int Outputs>
+class bbd_device_base : public device_t, public device_sound_interface
+{
+protected:
+ // internal constructor
+ bbd_device_base(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, device_type type);
+
+ // override to convert clock to sample rate
+ virtual u32 sample_rate() const { return clock(); }
+
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_clock_changed() override;
+
+ // sound stream update overrides
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
+
+protected:
+ sound_stream * m_stream;
+ u32 m_curpos;
+ stream_buffer::sample_t m_buffer[Entries];
+};
+
+
+// ======================> mn3004_device
+
+class mn3004_device : public bbd_device_base<512, 2>
+{
+public:
+ mn3004_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+DECLARE_DEVICE_TYPE(MN3004, mn3004_device)
+
+
+// ======================> mn3005_device
+
+class mn3005_device : public bbd_device_base<4096, 2>
+{
+public:
+ mn3005_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+DECLARE_DEVICE_TYPE(MN3005, mn3005_device)
+
+
+// ======================> mn3006_device
+
+class mn3006_device : public bbd_device_base<128, 2>
+{
+public:
+ mn3006_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+DECLARE_DEVICE_TYPE(MN3006, mn3006_device)
+
+
+// ======================> mn3204p_device
+
+class mn3204p_device : public bbd_device_base<512, 2>
+{
+public:
+ mn3204p_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+DECLARE_DEVICE_TYPE(MN3204P, mn3204p_device)
+
+#endif // MAME_SOUND_BBD_H
diff --git a/src/devices/sound/mixer.cpp b/src/devices/sound/mixer.cpp
new file mode 100644
index 00000000000..3b8435182c4
--- /dev/null
+++ b/src/devices/sound/mixer.cpp
@@ -0,0 +1,30 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+#include "emu.h"
+#include "mixer.h"
+
+
+//**************************************************************************
+// MIXER DEVICE
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(MIXER, mixer_device, "mixer", "Generic Audio Mixer")
+
+//-------------------------------------------------
+// mixer_device - constructor
+//-------------------------------------------------
+
+mixer_device::mixer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, MIXER, tag, owner, clock),
+ device_mixer_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mixer_device::device_start()
+{
+}
diff --git a/src/devices/sound/mixer.h b/src/devices/sound/mixer.h
new file mode 100644
index 00000000000..e25466ea351
--- /dev/null
+++ b/src/devices/sound/mixer.h
@@ -0,0 +1,27 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+#ifndef MAME_SOUND_MIXER_H
+#define MAME_SOUND_MIXER_H
+
+#pragma once
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+DECLARE_DEVICE_TYPE(MIXER, mixer_device)
+
+// ======================> mixer_device
+
+class mixer_device : public device_t, public device_mixer_interface
+{
+public:
+ // internal constructor
+ mixer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+};
+
+#endif // MAME_SOUND_MIXER_H
diff --git a/src/devices/sound/ym2154.cpp b/src/devices/sound/ym2154.cpp
new file mode 100644
index 00000000000..2ad1bbac1fa
--- /dev/null
+++ b/src/devices/sound/ym2154.cpp
@@ -0,0 +1,311 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+#include "emu.h"
+#include "ym2154.h"
+
+
+//**************************************************************************
+// YM2154 DEVICE
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(YM2154, ym2154_device, "ym2154", "YM2154 (RYP4)")
+
+//-------------------------------------------------
+// ym2154_device - constructor
+//-------------------------------------------------
+
+ym2154_device::ym2154_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, YM2154, tag, owner, clock),
+ device_sound_interface(mconfig, *this),
+ device_memory_interface(mconfig, *this),
+ m_stream(nullptr),
+ m_timer(nullptr),
+ m_update_irq(*this),
+ m_io_read(*this),
+ m_io_write(*this),
+ m_group0_config("group0", ENDIANNESS_LITTLE, 8, 18, 0),
+ m_group1_config("group1", ENDIANNESS_LITTLE, 8, 18, 0),
+ m_group0_region(*this, "group0"),
+ m_group1_region(*this, "group1")
+{
+}
+
+
+//-------------------------------------------------
+// read - handle a device read
+//-------------------------------------------------
+
+u8 ym2154_device::read(offs_t offset)
+{
+ u8 result = 0xff;
+ switch (offset & 0x7f)
+ {
+ case 0x01: // A/D converter registers
+ case 0x02: // A/D converter registers
+ case 0x03: // A/D converter registers
+ case 0x04: // A/D converter registers
+ case 0x05: // A/D converter registers
+ case 0x06: // A/D converter registers
+ case 0x07: // A/D converter registers
+ case 0x08: // A/D converter registers
+ case 0x09: // A/D converter registers
+ case 0x0a: // A/D converter registers
+ result = m_io_read.isnull() ? 0 : m_io_read(offset - 1);
+ break;
+
+ case 0x0e: // IRQ ack
+ update_irq_state(0);
+ result = m_irq_count;
+ break;
+ }
+ return result;
+}
+
+
+//-------------------------------------------------
+// write - handle a device write
+//-------------------------------------------------
+
+void ym2154_device::write(offs_t offset, u8 data)
+{
+ m_stream->update();
+
+ u8 chan = BIT(offset, 0, 3);
+ u8 old;
+ switch (offset & 0x7f)
+ {
+ // timer count
+ case 0x02:
+ if (BIT(data, 7) != 0)
+ m_timer_count = (m_timer_count & 0x0f) | (BIT(data, 0, 7) << 4);
+ else
+ m_timer_count = (m_timer_count & 0x7f0) | BIT(data, 0, 4);
+ break;
+
+ // timer enable/output
+ case 0x03:
+ old = m_timer_enable;
+ m_timer_enable = BIT(data, 2);
+ if (!m_timer_enable)
+ m_timer->enable(false);
+ else if (m_timer_enable && !old)
+ m_timer->adjust((2048 - m_timer_count) * attotime::from_hz(sample_rate()));
+ if (!m_io_write.isnull())
+ m_io_write(0, BIT(data, 4, 4) ^ 0x0f);
+ break;
+
+ // output level
+ case 0x04:
+ m_total_level = BIT(data, 0, 6);
+ break;
+
+ // group 1 trigger
+ case 0x05:
+ for (int chan = 0; chan < 6; chan++)
+ if (BIT(data, chan))
+ m_channel[6 + chan].start();
+ break;
+
+ // group 0 trigger
+ case 0x06:
+ for (int chan = 0; chan < 6; chan++)
+ if (BIT(data, chan))
+ m_channel[0 + chan].start();
+ break;
+
+ // DAC mode (not implemented)
+ case 0x07:
+ break;
+
+ // pan
+ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d:
+ m_channel[0 + chan].m_panpot = BIT(data, 0, 4);
+ m_channel[6 + chan].m_panpot = BIT(data, 4, 4);
+ break;
+
+ // rate/level, group 0
+ case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15:
+ m_channel[0 + chan].m_output_level = BIT(data, 0, 5);
+ m_channel[0 + chan].m_rate = BIT(data, 5, 2);
+ break;
+
+ // rate/level, group 1
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d:
+ m_channel[6 + chan].m_output_level = BIT(data, 0, 5);
+ m_channel[6 + chan].m_rate = BIT(data, 5, 2);
+ break;
+
+ // sample position A, group 0
+ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25:
+ m_channel[0 + chan].m_start = (m_channel[0 + chan].m_start & 0x0f) | (data << 4);
+ break;
+
+ // sample position B, group 0
+ case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d:
+ m_channel[0 + chan].m_start = (m_channel[0 + chan].m_start & 0xff0) | (data >> 4);
+ m_channel[0 + chan].m_end = (m_channel[0 + chan].m_end & 0xff) | ((data & 0xf) << 8);
+ break;
+
+ // sample position C, group 0
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35:
+ m_channel[0 + chan].m_end = (m_channel[0 + chan].m_end & 0xf00) | data;
+ break;
+
+ // sample position A, group 1
+ case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d:
+ m_channel[6 + chan].m_start = (m_channel[6 + chan].m_start & 0x0f) | (data << 4);
+ break;
+
+ // sample position B, group 1
+ case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45:
+ m_channel[6 + chan].m_start = (m_channel[6 + chan].m_start & 0xff0) | (data >> 4);
+ m_channel[6 + chan].m_end = (m_channel[6 + chan].m_end & 0xff) | ((data & 0xf) << 8);
+ break;
+
+ // sample position C, group 1
+ case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d:
+ m_channel[6 + chan].m_end = (m_channel[6 + chan].m_end & 0xf00) | data;
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void ym2154_device::device_start()
+{
+ // allocate our timer
+ m_timer = timer_alloc(0);
+
+ // resolve the handlers
+ m_update_irq.resolve();
+ m_io_read.resolve();
+ m_io_write.resolve();
+
+ // allocate our stream
+ m_stream = stream_alloc(0, 2, sample_rate());
+
+ // now register the blob for save, on the assumption the size won't change
+ save_item(NAME(m_timer_count));
+ save_item(NAME(m_timer_enable));
+ save_item(NAME(m_irq_state));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_total_level));
+ save_item(STRUCT_MEMBER(m_channel, m_pos));
+ save_item(STRUCT_MEMBER(m_channel, m_start));
+ save_item(STRUCT_MEMBER(m_channel, m_end));
+ save_item(STRUCT_MEMBER(m_channel, m_panpot));
+ save_item(STRUCT_MEMBER(m_channel, m_output_level));
+ save_item(STRUCT_MEMBER(m_channel, m_rate));
+
+ // automatically map memory regions if not configured externally
+ if (!has_configured_map(0) && !has_configured_map(1))
+ {
+ if (m_group0_region)
+ space(0).install_rom(0, m_group0_region->bytes() - 1, m_group0_region->base());
+
+ if (m_group1_region)
+ space(1).install_rom(0, m_group1_region->bytes() - 1, m_group1_region->base());
+ else if (m_group0_region)
+ space(1).install_rom(0, m_group0_region->bytes() - 1, m_group0_region->base());
+ }
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void ym2154_device::device_reset()
+{
+ for (int chan = 0; chan < 12; chan++)
+ m_channel[chan].m_pos = 0xfffffff;
+}
+
+
+//-------------------------------------------------
+// device_clock_changed - clock changed signal
+//-------------------------------------------------
+
+void ym2154_device::device_clock_changed()
+{
+ if (m_stream != nullptr)
+ m_stream->set_sample_rate(sample_rate());
+}
+
+
+//-------------------------------------------------
+// sound_stream_update - generate sound data
+//-------------------------------------------------
+
+void ym2154_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ update_irq_state(1);
+ m_timer->adjust((2048 - m_timer_count) * attotime::from_hz(sample_rate()));
+}
+
+
+//-------------------------------------------------
+// sound_stream_update - generate sound data
+//-------------------------------------------------
+
+void ym2154_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
+{
+ static const uint16_t voltable[8] = { 0x7fa,0x751,0x6b5,0x627,0x5a4,0x52c,0x4be,0x45a };
+
+ auto &outl = outputs[0];
+ auto &outr = outputs[1];
+
+ outl.fill(0);
+ outr.fill(0);
+
+ for (int chan = 0; chan < 12; chan++)
+ {
+ auto &channel = m_channel[chan];
+
+ // not sure how the "rate" really works but it's used to stop a sample from
+ // playing so just treat it as such
+ if (channel.m_rate == 3)
+ m_channel[chan].m_pos = 0xfffffff;
+
+ if ((channel.m_pos >> ADDR_SHIFT) <= channel.m_end && channel.m_panpot != 0)
+ {
+ uint32_t vol = (channel.m_output_level ^ 0x1f) + (m_total_level ^ 0x3f);
+
+ uint32_t lvol = vol;
+ if (channel.m_panpot > 8)
+ lvol += 4 * (channel.m_panpot - 8);
+ lvol = voltable[lvol & 7] >> (lvol >> 3);
+
+ uint32_t rvol = vol;
+ if (channel.m_panpot < 7)
+ rvol += 4 * (7 - channel.m_panpot);
+ rvol = voltable[rvol & 7] >> (rvol >> 3);
+
+ for (int sampindex = 0; sampindex < outl.samples() && (channel.m_pos >> ADDR_SHIFT) <= channel.m_end; sampindex++)
+ {
+ // unsure what the real data is; for now guessing 8-bit PCM but could
+ // be ADPCM-A or some other format
+ int8_t data = space(chan / 6).read_byte(channel.m_pos++);
+ outl.add_int(sampindex, data * lvol, 0x80 * 0x800);
+ outr.add_int(sampindex, data * rvol, 0x80 * 0x800);
+ }
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+device_memory_interface::space_config_vector ym2154_device::memory_space_config() const
+{
+ return space_config_vector{
+ std::make_pair(0, &m_group0_config),
+ std::make_pair(1, &m_group1_config)
+ };
+}
diff --git a/src/devices/sound/ym2154.h b/src/devices/sound/ym2154.h
new file mode 100644
index 00000000000..58976f0177b
--- /dev/null
+++ b/src/devices/sound/ym2154.h
@@ -0,0 +1,99 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+#ifndef MAME_SOUND_YM2154_H
+#define MAME_SOUND_YM2154_H
+
+#pragma once
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+DECLARE_DEVICE_TYPE(YM2154, ym2154_device)
+
+// ======================> ym2154_device
+
+class ym2154_device : public device_t, public device_sound_interface, public device_memory_interface
+{
+ static constexpr uint8_t ADDR_SHIFT = 6;
+
+public:
+ // internal constructor
+ ym2154_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // configuration helpers
+ auto irq_handler() { return m_update_irq.bind(); }
+ auto io_read_handler() { return m_io_read.bind(); }
+ auto io_write_handler() { return m_io_write.bind(); }
+
+ // register reads
+ u8 read(offs_t offset);
+
+ // register writes
+ void write(offs_t offset, u8 data);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_clock_changed() override;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ // sound overrides
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
+
+ // memory space configuration
+ virtual space_config_vector memory_space_config() const override;
+
+private:
+ struct channel
+ {
+ channel() :
+ m_pos(0xfffffff), m_start(0), m_end(0), m_panpot(0), m_output_level(0), m_rate(0) { }
+
+ void reset()
+ {
+ m_pos = 0;
+ m_start = m_end = 0;
+ m_panpot = 0;
+ m_output_level = 0;
+ m_rate = 0;
+ }
+
+ void start()
+ {
+ m_pos = m_start << ADDR_SHIFT;
+ }
+
+ uint32_t m_pos;
+ uint16_t m_start;
+ uint16_t m_end;
+ uint8_t m_panpot;
+ uint8_t m_output_level;
+ uint8_t m_rate;
+ };
+
+ // internal helpers
+ u32 sample_rate() const { return device_t::clock() / 18 / 6; }
+ void update_irq_state(u8 state) { if (m_irq_state != state) { m_irq_state = state; m_update_irq(state); } }
+
+ // internal state
+ sound_stream *m_stream; // sound stream
+ emu_timer *m_timer; // two timers
+ uint16_t m_timer_count; // current timer count
+ uint8_t m_timer_enable; // timer enable
+ uint8_t m_irq_state; // current IRQ state
+ uint8_t m_irq_count; // current IRQ count
+ uint8_t m_total_level; // master volume
+ channel m_channel[12]; // output channels
+ devcb_write_line m_update_irq; // IRQ update callback
+ devcb_read8 m_io_read; // input port handler
+ devcb_write8 m_io_write; // output port handler
+ address_space_config const m_group0_config; // address space 0 config
+ address_space_config const m_group1_config; // address space 1 config
+ optional_memory_region m_group0_region; // group 0 memory region
+ optional_memory_region m_group1_region; // group 1 memory region
+};
+
+
+#endif // MAME_SOUND_YM2154_H
diff --git a/src/mame/drivers/ympsr60.cpp b/src/mame/drivers/ympsr60.cpp
index 80528354359..546ade171e6 100644
--- a/src/mame/drivers/ympsr60.cpp
+++ b/src/mame/drivers/ympsr60.cpp
@@ -46,6 +46,9 @@
#include "machine/i8255.h"
#include "machine/6850acia.h"
#include "machine/clock.h"
+#include "sound/bbd.h"
+#include "sound/mixer.h"
+#include "sound/ym2154.h"
#include "sound/ymopq.h"
#include "bus/midi/midi.h"
@@ -68,12 +71,17 @@ public:
m_ym3533(*this, "ym3533"),
m_ppi(*this, "ppi"),
m_acia(*this, "acia"),
+ m_lmixer(*this, "lmixer"),
+ m_rmixer(*this, "rmixer"),
+ m_bbd(*this, "bbd"),
+ m_ryp4(*this, "ryp4"),
m_rom2bank(*this, "rom2bank"),
m_keyboard(*this, "P1_%u", 0),
m_drvif(*this, "DRVIF_%u", 0),
m_drvif_out(*this, "DRVIF_%u_DP%u", 0U, 1U),
m_ryp4_in(*this, "RYP4_%u", 1U),
- m_ryp4_out(*this, "RYP4_%u", 1U)
+ m_ryp4_out(*this, "RYP4_%u", 1U),
+ m_mastervol(*this, "MASTERVOL")
{ }
void psr_common(machine_config &config);
@@ -83,21 +91,24 @@ public:
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
private:
required_device<z80_device> m_maincpu;
required_device<ym3533_device> m_ym3533;
required_device<i8255_device> m_ppi;
required_device<acia6850_device> m_acia;
+ required_device<mixer_device> m_lmixer;
+ required_device<mixer_device> m_rmixer;
+ required_device<mn3204p_device> m_bbd;
+ required_device<ym2154_device> m_ryp4;
required_memory_bank m_rom2bank;
required_ioport_array<10> m_keyboard;
required_ioport_array<DRVIF_MAX_TARGETS> m_drvif;
output_finder<DRVIF_MAX_TARGETS, 4> m_drvif_out;
required_ioport_array<RYP4_MAX_TARGETS> m_ryp4_in;
output_finder<RYP4_MAX_TARGETS> m_ryp4_out;
- u8 m_ym2154_regs[0x80];
- u16 m_ym2154_tempo;
- emu_timer *m_ym2154_timer;
+ required_ioport m_mastervol;
void psr60_map(address_map &map);
void psr60_io_map(address_map &map);
@@ -109,25 +120,24 @@ private:
int m_acia_irq, m_ym_irq, m_drvif_irq, m_ym2154_irq;
u16 m_keyboard_select;
+ u8 m_bbd_config;
u8 m_drvif_data[2];
u8 m_drvif_select;
WRITE_LINE_MEMBER(write_acia_clock) { m_acia->write_txc(state); m_acia->write_rxc(state); }
WRITE_LINE_MEMBER(acia_irq_w) { m_acia_irq = state; recalc_irqs(); }
-
WRITE_LINE_MEMBER(ym_irq_w) { m_ym_irq = state; recalc_irqs(); }
+ WRITE_LINE_MEMBER(ryp4_irq_w) { m_ym2154_irq = state; recalc_irqs(); }
+
+ u8 ryp4_an_r(offs_t offset);
+ void ryp4_out_w(u8 data);
u8 drvif_r(offs_t offset);
void drvif_w(offs_t offset, u8 data);
- u8 ym2154_r(offs_t offset);
- void ym2154_w(offs_t offset, u8 data);
- attotime ym2154_period(u32 tempo) const { return attotime::from_hz(2250000 / 12 / 8) * (2048 - tempo); }
-
public:
INPUT_CHANGED_MEMBER(drvif_changed);
- INPUT_CHANGED_MEMBER(ryp4_changed);
- TIMER_CALLBACK_MEMBER(ym2154_timer);
+ INPUT_CHANGED_MEMBER(mastervol_changed);
};
void psr60_state::psr60_map(address_map &map)
@@ -138,148 +148,13 @@ void psr60_state::psr60_map(address_map &map)
map(0xe000, 0xffff).ram(); // work RAM
}
-//
-// YM2154 - ROMpler with I/O ports
-//
-// Chip is clocked at 2.25MHz
-//
-// Some of this looks suspiciously like 2x the ADPCM-A attached to the
-// YM2608: 6 channels (2 banks), total level and instrument levels behave
-// the same.
-//
-// Start/end addresses are 9 bits to address 32k ROMs (15 bits) so
-// presume a left shift of 6 (actually 7 if 4-bit ADPCM data).
-//
-// Two serial ROMs are connected, containing 32k of sample data each.
-// It appears that the channel bank (0-5 vs 6-11) implies which of the
-// two ROMs is read.
-//
-// System-wide registers:
-// 01 -------- Unknown ($00 written at init)
-// 02 1xxxxxxx Timer upper bits latch
-// 0---xxxx Timer lower bits
-// 03 -x------ Unknown (IRQ enable?)
-// -----x-- Timer enable
-// 04 --xxxxxx Master volume (0=min, 3F=max)
-// 05 --xxxxxx Bank 2 key on/off
-// 06 --xxxxxx Bank 1 key on/off
-// 07 -------x Unknown ($01 written at init)
-//
-// Per-channel registers (channel in address bits 0-2)
-// 08-0D -------- Unknown; written as two nibbles so shared between banks
-// 10-15 -xx----- Bank 1 Write 11 here to disable?
-// ---xxxxx Bank 1 Instrument volume (0=min, 1F=max)
-// 18-1D -xx----- Bank 2 Write 11 here to disable?
-// ---xxxxx Bank 2 Instrument volume (0=min, 1F=max)
-// 20-25 ---xxxxx Bank 1 Start address upper bits
-// 28-2D xxxx---- Bank 1 Start address lower bits
-// -------x Bank 1 End address upper bits
-// 30-35 xxxxxxxx Bank 1 End address lower bits
-// 38-3D ---xxxxx Bank 2 Start address upper bits
-// 40-45 xxxx---- Bank 2 Start address lower bits
-// -------x Bank 2 End address upper bits
-// 48-4D xxxxxxxx Bank 2 End address lower bits
-//
-// Reads:
-// 01-0A xxxxxxxx AN1-10 digital values
-// 0E -------- IRQ clear?
-//
-
-u8 psr60_state::ym2154_r(offs_t offset)
-{
- u8 result = 0;
-
- // read analog inputs
- if (offset >= 1 && offset <= 10)
- {
- if (offset - 1 < RYP4_MAX_TARGETS)
- result = m_ryp4_in[offset - 1]->read();
- }
- else if (offset == 14)
- {
- m_ym2154_irq = 0;
- recalc_irqs();
- }
- else
- printf("YM2154: Read %02X\n", offset);
-
- return result;
-}
-
-void psr60_state::ym2154_w(offs_t offset, u8 data)
-{
-// printf("YM2154: Write %02X=%02X\n", offset, data);
- u8 old = m_ym2154_regs[offset];
- m_ym2154_regs[offset] = data;
-
- // tempo
- if (offset == 2)
- {
- // two writes in succession
- if (BIT(data, 7) == 0 && BIT(old, 7) != 0)
- {
- m_ym2154_tempo = (BIT(old, 0, 7) << 4) | (data & 0xf);
- printf("YM2154: tempo = %03X\n", m_ym2154_tempo);
- }
- }
-
- // control
- else if (offset == 3)
- {
- if (BIT(old ^ data, 2) != 0)
- {
- if (BIT(data, 2) != 0)
- m_ym2154_timer->adjust(ym2154_period(m_ym2154_tempo));
- else
- m_ym2154_timer->enable(false);
- }
- }
-
- // total overall level
- else if (offset == 4)
- {
- }
-
- // key on
- else if (offset == 5)
- {
- for (int bit = 0; bit < 6; bit++)
- if (BIT(data, bit) != 0)
- printf("YM2154: Bank 2 Ch %d on: %03X-%03X vol=%02X low=%X\n", bit, (m_ym2154_regs[0x38+bit] << 4) | (m_ym2154_regs[0x40+bit] >> 4), ((m_ym2154_regs[0x40+bit] & 0x0f) << 8) | m_ym2154_regs[0x48+bit], m_ym2154_regs[0x18+bit], m_ym2154_regs[0x08+bit] >> 4);
- }
- else if (offset == 6)
- {
- for (int bit = 0; bit < 6; bit++)
- if (BIT(data, bit) != 0)
- printf("YM2154: Bank 1 Ch %d on: %03X-%03X vol=%02X low=%X\n", bit, (m_ym2154_regs[0x20+bit] << 4) | (m_ym2154_regs[0x28+bit] >> 4), ((m_ym2154_regs[0x28+bit] & 0x0f) << 8) | m_ym2154_regs[0x30+bit], m_ym2154_regs[0x10+bit], m_ym2154_regs[0x08+bit] & 0xf);
- }
- else if (offset < 8 || offset >= 0x50)
- printf("YM2154: Write %02X = %02X\n", offset, data);
-}
-
-TIMER_CALLBACK_MEMBER(psr60_state::ym2154_timer)
-{
- m_ym2154_irq = 1;
- recalc_irqs();
- if (BIT(m_ym2154_regs[3], 2) != 0)
- m_ym2154_timer->adjust(ym2154_period(m_ym2154_tempo));
-}
-
-INPUT_CHANGED_MEMBER(psr60_state::ryp4_changed)
-{
- // why does this crash? need to feed the values to an output to reflect
- // the sliders in the layout
-// m_ryp4_out[param] = m_ryp4_in[param]->read();
-}
-
-
void psr60_state::psr60_io_map(address_map &map)
{
map.global_mask(0xff); // top 8 bits of the address are ignored by this hardware for I/O access
map(0x10, 0x11).rw(m_acia, FUNC(acia6850_device::read), FUNC(acia6850_device::write));
map(0x20, 0x23).rw(m_ppi, FUNC(i8255_device::read), FUNC(i8255_device::write));
map(0x30, 0x3f).rw(FUNC(psr60_state::drvif_r), FUNC(psr60_state::drvif_w));
- map(0x80, 0xff).rw(FUNC(psr60_state::ym2154_r), FUNC(psr60_state::ym2154_w));
+ map(0x80, 0xff).rw(m_ryp4, FUNC(ym2154_device::read), FUNC(ym2154_device::write));
}
u8 psr60_state::ppi_pa_r()
@@ -302,6 +177,49 @@ void psr60_state::ppi_pc_w(u8 data)
m_keyboard_select = (m_keyboard_select & ~0x300) | ((data & 3) << 8);
}
+u8 psr60_state::ryp4_an_r(offs_t offset)
+{
+ return (offset < RYP4_MAX_TARGETS) ? (m_ryp4_in[offset]->read() * 255 / 100) : 0;
+}
+
+void psr60_state::ryp4_out_w(u8 data)
+{
+ m_bbd_config = data;
+
+ // bit 0 (CT0) enables/disables the effect
+ m_bbd->set_output_gain(0, BIT(data, 0) ? 1.0 : 0.0);
+
+ // bits 1 + 2 go to the 'T' and 'C' pins and control the frequency
+ // modulation, which we simulate in a periodic timer
+}
+
+void psr60_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ // only two states have been observed to be measured: CT1=1/CT2=0 and CT1=0/CT2=1
+ attotime curtime = machine().time();
+ double bbd_freq;
+ if (BIT(m_bbd_config, 1) && !BIT(m_bbd_config, 2))
+ {
+ // Stereo symphonic off: min freq 35 kHz, max freq 107 kHz, varies at 0,3 Hz
+ curtime.m_seconds %= 3;
+ double pos = curtime.as_double() / 3;
+ pos = (pos < 0.5) ? (2 * pos) : 2 * (1.0 - pos);
+ bbd_freq = 35 + (107 - 35) * pos;
+ }
+ else
+ {
+ // Stereo symphonic on: min freq 48 kHz, max freq 61 kHz, varies at 6 Hz
+ curtime.m_seconds = 0;
+ double pos = curtime.as_double() * 6;
+ pos -= floor(pos);
+ pos = (pos < 0.5) ? (2 * pos) : 2 * (1.0 - pos);
+ bbd_freq = 48 + (61 - 48) * pos;
+ }
+
+ // two out-of-phase clocks run the BBD so it's effectively 2x frequency
+ m_bbd->set_unscaled_clock(bbd_freq * 2);
+}
+
//
// DRVIF: driver interface chip
//
@@ -345,6 +263,13 @@ INPUT_CHANGED_MEMBER(psr60_state::drvif_changed)
recalc_irqs();
}
+INPUT_CHANGED_MEMBER(psr60_state::mastervol_changed)
+{
+ float mastervol = m_mastervol->read() / 75.0;
+ m_lmixer->set_output_gain(0, mastervol);
+ m_rmixer->set_output_gain(0, mastervol);
+}
+
void psr60_state::recalc_irqs()
{
int irq_state = m_acia_irq | m_ym_irq | m_drvif_irq | m_ym2154_irq;
@@ -357,8 +282,7 @@ void psr60_state::machine_start()
m_rom2bank->configure_entries(0, 2, memregion("rom2")->base(), 0x4000);
m_rom2bank->set_entry(0);
m_acia_irq = CLEAR_LINE;
-
- m_ym2154_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(psr60_state::ym2154_timer), this));
+ timer_alloc()->adjust(attotime::from_hz(50), 0, attotime::from_hz(50));
}
void psr60_state::machine_reset()
@@ -374,7 +298,7 @@ void psr60_state::machine_reset()
#define RYP4_PORT(num, name) \
PORT_START("RYP4_" #num) \
- PORT_ADJUSTER(0xc0, name) PORT_MINMAX(0x00, 0xff) PORT_CHANGED_MEMBER(DEVICE_SELF, psr60_state, ryp4_changed, num - 1)
+ PORT_ADJUSTER(75, name)
static INPUT_PORTS_START(psr60)
PORT_START("P1_9")
@@ -497,6 +421,9 @@ static INPUT_PORTS_START(psr60)
RYP4_PORT(6, "Bass Volume")
RYP4_PORT(7, "Unused7")
RYP4_PORT(8, "Unused8")
+
+ PORT_START("MASTERVOL")
+ PORT_ADJUSTER(75, "Master Volume") PORT_CHANGED_MEMBER(DEVICE_SELF, psr60_state, mastervol_changed, 0)
INPUT_PORTS_END
static INPUT_PORTS_START(psr70)
@@ -632,6 +559,9 @@ static INPUT_PORTS_START(psr70)
RYP4_PORT(6, "Bass Volume")
RYP4_PORT(7, "Unused7")
RYP4_PORT(8, "Unused8")
+
+ PORT_START("MASTERVOL")
+ PORT_ADJUSTER(75, "Master Volume") PORT_CHANGED_MEMBER(DEVICE_SELF, psr60_state, mastervol_changed, 0)
INPUT_PORTS_END
void psr60_state::psr_common(machine_config &config)
@@ -660,10 +590,30 @@ void psr60_state::psr_common(machine_config &config)
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
+ MIXER(config, m_lmixer);
+ m_lmixer->add_route(0, "lspeaker", 1.0);
+
+ MIXER(config, m_rmixer);
+ m_rmixer->add_route(0, "rspeaker", 1.0);
+
+ YM2154(config, m_ryp4, 2250000);
+ m_ryp4->irq_handler().set(FUNC(psr60_state::ryp4_irq_w));
+ m_ryp4->io_read_handler().set(FUNC(psr60_state::ryp4_an_r));
+ m_ryp4->io_write_handler().set(FUNC(psr60_state::ryp4_out_w));
+ m_ryp4->add_route(0, m_lmixer, 0.50); // rhythm channels are mixed in separately
+ m_ryp4->add_route(1, m_rmixer, 0.50);
+
+ MN3204P(config, m_bbd, 12700); // 6.7kHz feeds the iG10090 driver, range is 10-200kHz
+ m_bbd->add_route(0, m_lmixer, 0.11); // BBD is mixed in
+ m_bbd->add_route(0, m_rmixer, 0.11);
+
YM3533(config, m_ym3533, 3.579545_MHz_XTAL);
m_ym3533->irq_handler().set(FUNC(psr60_state::ym_irq_w));
- m_ym3533->add_route(0, "lspeaker", 1.0);
- m_ym3533->add_route(1, "rspeaker", 1.0);
+ m_ym3533->add_route(0, m_lmixer, 0.16); // channel 1 = ORC
+ m_ym3533->add_route(0, m_rmixer, 0.16);
+ m_ym3533->add_route(0, m_bbd, 1.0);
+ m_ym3533->add_route(1, m_lmixer, 0.22); // channel 2 = SABC
+ m_ym3533->add_route(1, m_rmixer, 0.22);
}
void psr60_state::psr60(machine_config &config)
@@ -684,6 +634,12 @@ ROM_START( psr60 )
ROM_REGION(0x8000, "rom2", 0)
ROM_LOAD("yamaha_psr60_pgm_ic110.bin", 0x000000, 0x008000, CRC(39db8c74) SHA1(7750104d1e5df3357aa553ac58768dbc34051cd8))
+
+ ROM_REGION(0x8000, "ryp4:group0", 0)
+ ROM_LOAD("ym21908.bin", 0x0000, 0x8000, CRC(4ed0d9dc) SHA1(aed7ab6f1c9e28fdf259cb932136b12845040d79) BAD_DUMP)
+
+ ROM_REGION(0x8000, "ryp4:group1", 0)
+ ROM_LOAD("ym21909.bin", 0x0000, 0x8000, CRC(bb9bb698) SHA1(76563d1f25152cd54041019ef7bc264ede0d8b2b) BAD_DUMP)
ROM_END
ROM_START(psr70)
@@ -692,6 +648,12 @@ ROM_START(psr70)
ROM_REGION(0x8000, "rom2", 0)
ROM_LOAD("yamaha_psr60_pgm_ic110.bin", 0x000000, 0x008000, CRC(39db8c74) SHA1(7750104d1e5df3357aa553ac58768dbc34051cd8))
+
+ ROM_REGION(0x8000, "ryp4:group0", 0)
+ ROM_LOAD("ym21908.bin", 0x0000, 0x8000, CRC(4ed0d9dc) SHA1(aed7ab6f1c9e28fdf259cb932136b12845040d79) BAD_DUMP)
+
+ ROM_REGION(0x8000, "ryp4:group1", 0)
+ ROM_LOAD("ym21909.bin", 0x0000, 0x8000, CRC(bb9bb698) SHA1(76563d1f25152cd54041019ef7bc264ede0d8b2b) BAD_DUMP)
ROM_END
CONS(1985, psr60, 0, 0, psr60, psr60, psr60_state, empty_init, "Yamaha", "PSR-60 PortaSound", MACHINE_NOT_WORKING | MACHINE_CLICKABLE_ARTWORK)
diff --git a/src/mame/layout/psr60.lay b/src/mame/layout/psr60.lay
index e008753326a..7fd4d694efd 100644
--- a/src/mame/layout/psr60.lay
+++ b/src/mame/layout/psr60.lay
@@ -279,6 +279,61 @@ license:CC0
<rect><bounds x="11" y="2" width="150" height="19" /><color red="0.3" green="0.3" blue="0.3" /></rect>
</element>
+ <element name="slider-bar-white">
+ <disk><bounds x="0" y="0" width="23" height="23" /><color red="0.0" green="0.0" blue="0.0" /></disk>
+ <disk><bounds x="41" y="0" width="23" height="23" /><color red="0.0" green="0.0" blue="0.0" /></disk>
+ <rect><bounds x="11" y="0" width="40" height="23" /><color red="0.0" green="0.0" blue="0.0" /></rect>
+ <disk><bounds x="2" y="2" width="19" height="19" /><color red="0.3" green="0.3" blue="0.3" /></disk>
+ <disk><bounds x="43" y="2" width="19" height="19" /><color red="0.3" green="0.3" blue="0.3" /></disk>
+ <rect><bounds x="11" y="2" width="40" height="19" /><color red="0.3" green="0.3" blue="0.3" /></rect>
+ <rect><bounds x="30" y="2" width="5" height="19" /><color red="1.0" green="1.0" blue="1.0" /></rect>
+ </element>
+ <element name="slider-bar-green">
+ <disk><bounds x="0" y="0" width="23" height="23" /><color red="0.0" green="0.0" blue="0.0" /></disk>
+ <disk><bounds x="41" y="0" width="23" height="23" /><color red="0.0" green="0.0" blue="0.0" /></disk>
+ <rect><bounds x="11" y="0" width="40" height="23" /><color red="0.0" green="0.0" blue="0.0" /></rect>
+ <disk><bounds x="2" y="2" width="19" height="19" /><color red="0.3" green="0.3" blue="0.3" /></disk>
+ <disk><bounds x="43" y="2" width="19" height="19" /><color red="0.3" green="0.3" blue="0.3" /></disk>
+ <rect><bounds x="11" y="2" width="40" height="19" /><color red="0.3" green="0.3" blue="0.3" /></rect>
+ <rect><bounds x="30" y="2" width="5" height="19" /><color red="0.5" green="1.0" blue="0.5" /></rect>
+ </element>
+ <element name="slider-bar-yellow">
+ <disk><bounds x="0" y="0" width="23" height="23" /><color red="0.0" green="0.0" blue="0.0" /></disk>
+ <disk><bounds x="41" y="0" width="23" height="23" /><color red="0.0" green="0.0" blue="0.0" /></disk>
+ <rect><bounds x="11" y="0" width="40" height="23" /><color red="0.0" green="0.0" blue="0.0" /></rect>
+ <disk><bounds x="2" y="2" width="19" height="19" /><color red="0.3" green="0.3" blue="0.3" /></disk>
+ <disk><bounds x="43" y="2" width="19" height="19" /><color red="0.3" green="0.3" blue="0.3" /></disk>
+ <rect><bounds x="11" y="2" width="40" height="19" /><color red="0.3" green="0.3" blue="0.3" /></rect>
+ <rect><bounds x="30" y="2" width="5" height="19" /><color red="1.0" green="1.0" blue="0.5" /></rect>
+ </element>
+ <element name="slider-bar-blue">
+ <disk><bounds x="0" y="0" width="23" height="23" /><color red="0.0" green="0.0" blue="0.0" /></disk>
+ <disk><bounds x="41" y="0" width="23" height="23" /><color red="0.0" green="0.0" blue="0.0" /></disk>
+ <rect><bounds x="11" y="0" width="40" height="23" /><color red="0.0" green="0.0" blue="0.0" /></rect>
+ <disk><bounds x="2" y="2" width="19" height="19" /><color red="0.3" green="0.3" blue="0.3" /></disk>
+ <disk><bounds x="43" y="2" width="19" height="19" /><color red="0.3" green="0.3" blue="0.3" /></disk>
+ <rect><bounds x="11" y="2" width="40" height="19" /><color red="0.3" green="0.3" blue="0.3" /></rect>
+ <rect><bounds x="30" y="2" width="5" height="19" /><color red="0.5" green="0.5" blue="1.0" /></rect>
+ </element>
+ <element name="slider-bar-red">
+ <disk><bounds x="0" y="0" width="23" height="23" /><color red="0.0" green="0.0" blue="0.0" /></disk>
+ <disk><bounds x="41" y="0" width="23" height="23" /><color red="0.0" green="0.0" blue="0.0" /></disk>
+ <rect><bounds x="11" y="0" width="40" height="23" /><color red="0.0" green="0.0" blue="0.0" /></rect>
+ <disk><bounds x="2" y="2" width="19" height="19" /><color red="0.3" green="0.3" blue="0.3" /></disk>
+ <disk><bounds x="43" y="2" width="19" height="19" /><color red="0.3" green="0.3" blue="0.3" /></disk>
+ <rect><bounds x="11" y="2" width="40" height="19" /><color red="0.3" green="0.3" blue="0.3" /></rect>
+ <rect><bounds x="30" y="2" width="5" height="19" /><color red="1.0" green="0.2" blue="0.2" /></rect>
+ </element>
+ <element name="slider-bar-grey">
+ <disk><bounds x="0" y="0" width="23" height="23" /><color red="0.0" green="0.0" blue="0.0" /></disk>
+ <disk><bounds x="41" y="0" width="23" height="23" /><color red="0.0" green="0.0" blue="0.0" /></disk>
+ <rect><bounds x="11" y="0" width="40" height="23" /><color red="0.0" green="0.0" blue="0.0" /></rect>
+ <disk><bounds x="2" y="2" width="19" height="19" /><color red="0.3" green="0.3" blue="0.3" /></disk>
+ <disk><bounds x="43" y="2" width="19" height="19" /><color red="0.3" green="0.3" blue="0.3" /></disk>
+ <rect><bounds x="11" y="2" width="40" height="19" /><color red="0.3" green="0.3" blue="0.3" /></rect>
+ <rect><bounds x="30" y="2" width="5" height="19" /><color red="0.6" green="0.6" blue="0.6" /></rect>
+ </element>
+
<!-- LED primitive -->
<element name="led" defstate="0">
<disk state="0"><color red="0.4" green="0.3" blue="0.3" /></disk>
@@ -388,11 +443,17 @@ license:CC0
<element ref="power"><bounds x="177" y="165" width="82" height="17" /></element>
<element ref="led" name="DRVIF_0_DP4"><bounds x="213" y="188" width="12" height="12" /></element>
<element ref="slider-power"><bounds x="177" y="209" width="82" height="23" /></element>
+ <element ref="slider-bar-red"><bounds x="193" y="209" width="64" height="23" /></element>
<element ref="mastervolume"><bounds x="177" y="307" width="139" height="17" /></element>
<element ref="slidermin"><bounds x="177" y="336" width="139" height="13" /></element>
<element ref="slidermax"><bounds x="177" y="336" width="139" height="13" /></element>
<element ref="slider"><bounds x="177" y="352" width="139" height="23" /></element>
+ <element ref="slider-bar-grey">
+ <animate inputtag="MASTERVOL" mask="0xff" />
+ <bounds state="0" x="177" y="352" width="64" height="23" />
+ <bounds state="100" x="252" y="352" width="64" height="23" />
+ </element>
</group>
<!-- pitch group -->
@@ -451,11 +512,21 @@ license:CC0
<element ref="slidermin"><bounds x="567" y="338" width="139" height="12" /></element>
<element ref="slidermax"><bounds x="567" y="338" width="139" height="12" /></element>
<element ref="slider"><bounds x="567" y="352" width="139" height="23" /></element>
+ <element ref="slider-bar-blue">
+ <animate inputtag="RYP4_6" mask="0xff" />
+ <bounds state="0" x="567" y="352" width="64" height="23" />
+ <bounds state="100" x="642" y="352" width="64" height="23" />
+ </element>
<element ref="bassvolume"><bounds x="567" y="378" width="139" height="14" /></element>
<element ref="slidermin"><bounds x="727" y="338" width="139" height="12" /></element>
<element ref="slidermax"><bounds x="727" y="338" width="139" height="12" /></element>
<element ref="slider"><bounds x="727" y="352" width="139" height="23" /></element>
+ <element ref="slider-bar-blue">
+ <animate inputtag="RYP4_5" mask="0xff" />
+ <bounds state="0" x="727" y="352" width="64" height="23" />
+ <bounds state="100" x="802" y="352" width="64" height="23" />
+ </element>
<element ref="chordvolume"><bounds x="727" y="378" width="139" height="14" /></element>
</group>
@@ -553,11 +624,21 @@ license:CC0
<element ref="slidermin"><bounds x="923" y="338" width="139" height="12" /></element>
<element ref="slidermax"><bounds x="923" y="338" width="139" height="12" /></element>
<element ref="slider"><bounds x="923" y="352" width="139" height="23" /></element>
+ <element ref="slider-bar-yellow">
+ <animate inputtag="RYP4_3" mask="0xff" />
+ <bounds state="0" x="923" y="352" width="64" height="23" />
+ <bounds state="100" x="998" y="352" width="64" height="23" />
+ </element>
<element ref="volume"><bounds x="923" y="378" width="139" height="14" /></element>
<element ref="sliderslow"><bounds x="1081" y="338" width="174" height="12" /></element>
<element ref="sliderfast"><bounds x="1081" y="338" width="174" height="12" /></element>
<element ref="slider-tempo"><bounds x="1081" y="352" width="174" height="23" /></element>
+ <element ref="slider-bar-yellow">
+ <animate inputtag="RYP4_4" mask="0xff" />
+ <bounds state="0" x="1081" y="352" width="64" height="23" />
+ <bounds state="100" x="1191" y="352" width="64" height="23" />
+ </element>
<element ref="tempo"><bounds x="1081" y="378" width="174" height="14" /></element>
</group>
@@ -667,6 +748,11 @@ license:CC0
<element ref="slidermin"><bounds x="1597" y="338" width="139" height="12" /></element>
<element ref="slidermax"><bounds x="1597" y="338" width="139" height="12" /></element>
<element ref="slider"><bounds x="1597" y="352" width="139" height="23" /></element>
+ <element ref="slider-bar-green">
+ <animate inputtag="RYP4_2" mask="0xff" />
+ <bounds state="0" x="1597" y="352" width="64" height="23" />
+ <bounds state="100" x="1672" y="352" width="64" height="23" />
+ </element>
<element ref="volume"><bounds x="1597" y="378" width="139" height="14" /></element>
<element ref="button" inputtag="DRVIF_4" inputmask="0x80"><bounds x="1755" y="353" width="65" height="21" /></element>
@@ -750,6 +836,11 @@ license:CC0
<element ref="slidermin"><bounds x="2271" y="338" width="139" height="12" /></element>
<element ref="slidermax"><bounds x="2271" y="338" width="139" height="12" /></element>
<element ref="slider"><bounds x="2271" y="352" width="139" height="23" /></element>
+ <element ref="slider-bar-white">
+ <animate inputtag="RYP4_1" mask="0xff" />
+ <bounds state="0" x="2271" y="352" width="64" height="23" />
+ <bounds state="100" x="2346" y="352" width="64" height="23" />
+ </element>
<element ref="volume"><bounds x="2271" y="378" width="139" height="14" /></element>
<element ref="button" inputtag="DRVIF_13" inputmask="0x80"><bounds x="2429" y="353" width="65" height="21" /></element>
diff --git a/src/mame/layout/psr70.lay b/src/mame/layout/psr70.lay
index 102d7951f09..369f7355b12 100644
--- a/src/mame/layout/psr70.lay
+++ b/src/mame/layout/psr70.lay
@@ -268,6 +268,31 @@ license:CC0
<rect><bounds x="0" y="0" width="152" height="22" /><color red="0.0" green="0.0" blue="0.0" /></rect>
<rect><bounds x="2" y="2" width="148" height="18" /><color red="0.3" green="0.3" blue="0.3" /></rect>
</element>
+ <element name="slider-bar-grey">
+ <rect><bounds x="0" y="0" width="40" height="22" /><color red="0.0" green="0.0" blue="0.0" /></rect>
+ <rect><bounds x="2" y="2" width="36" height="18" /><color red="0.67" green="0.65" blue="0.65" /></rect>
+ <rect><bounds x="18" y="2" width="5" height="18" /><color red="1.0" green="1.0" blue="1.0" /></rect>
+ </element>
+ <element name="slider-bar-red">
+ <rect><bounds x="0" y="0" width="40" height="22" /><color red="0.0" green="0.0" blue="0.0" /></rect>
+ <rect><bounds x="2" y="2" width="36" height="18" /><color red="0.83" green="0.21" blue="0.19" /></rect>
+ <rect><bounds x="18" y="2" width="5" height="18" /><color red="1.0" green="1.0" blue="1.0" /></rect>
+ </element>
+ <element name="slider-bar-cyan">
+ <rect><bounds x="0" y="0" width="40" height="22" /><color red="0.0" green="0.0" blue="0.0" /></rect>
+ <rect><bounds x="2" y="2" width="36" height="18" /><color red="0.70" green="0.97" blue="0.96" /></rect>
+ <rect><bounds x="18" y="2" width="5" height="18" /><color red="1.0" green="1.0" blue="1.0" /></rect>
+ </element>
+ <element name="slider-bar-yellow">
+ <rect><bounds x="0" y="0" width="40" height="22" /><color red="0.0" green="0.0" blue="0.0" /></rect>
+ <rect><bounds x="2" y="2" width="36" height="18" /><color red="0.95" green="0.85" blue="0.58" /></rect>
+ <rect><bounds x="18" y="2" width="5" height="18" /><color red="1.0" green="1.0" blue="1.0" /></rect>
+ </element>
+ <element name="slider-bar-green">
+ <rect><bounds x="0" y="0" width="40" height="22" /><color red="0.0" green="0.0" blue="0.0" /></rect>
+ <rect><bounds x="2" y="2" width="36" height="18" /><color red="0.66" green="0.92" blue="0.78" /></rect>
+ <rect><bounds x="18" y="2" width="5" height="18" /><color red="1.0" green="1.0" blue="1.0" /></rect>
+ </element>
<!-- LED primitives -->
<element name="led" defstate="0">
@@ -384,11 +409,17 @@ license:CC0
<element ref="slidermin"><bounds x="689" y="468" width="136" height="13" /></element>
<element ref="slidermax"><bounds x="689" y="468" width="136" height="13" /></element>
<element ref="slider"><bounds x="699" y="480" width="116" height="22" /></element>
+ <element ref="slider-bar-grey">
+ <animate inputtag="MASTERVOL" mask="0xff" />
+ <bounds state="0" x="699" y="480" width="40" height="23" />
+ <bounds state="100" x="775" y="480" width="40" height="23" />
+ </element>
<element ref="mastervolume"><bounds x="699" y="504" width="139" height="13" /></element>
<element ref="slideroff"><bounds x="719" y="522" width="76" height="13" /></element>
<element ref="slideron"><bounds x="719" y="522" width="76" height="13" /></element>
<element ref="slider"><bounds x="699" y="534" width="116" height="22" /></element>
+ <element ref="slider-bar-red"><bounds x="755" y="534" width="40" height="23" /></element>
<element ref="power"><bounds x="699" y="558" width="116" height="13" /></element>
<element ref="led" name="DRVIF_0_DP4"><bounds x="820" y="539" width="12" height="12" /></element>
</group>
@@ -416,11 +447,21 @@ license:CC0
<element ref="slidermin"><bounds x="868" y="468" width="136" height="13" /></element>
<element ref="slidermax"><bounds x="868" y="468" width="136" height="13" /></element>
<element ref="slider"><bounds x="878" y="480" width="116" height="22" /></element>
+ <element ref="slider-bar-cyan">
+ <animate inputtag="RYP4_6" mask="0xff" />
+ <bounds state="0" x="878" y="480" width="40" height="23" />
+ <bounds state="100" x="954" y="480" width="40" height="23" />
+ </element>
<element ref="bassvolume"><bounds x="878" y="504" width="139" height="13" /></element>
<element ref="slidermin"><bounds x="868" y="522" width="136" height="13" /></element>
<element ref="slidermax"><bounds x="868" y="522" width="136" height="13" /></element>
<element ref="slider"><bounds x="878" y="534" width="116" height="22" /></element>
+ <element ref="slider-bar-cyan">
+ <animate inputtag="RYP4_5" mask="0xff" />
+ <bounds state="0" x="878" y="534" width="40" height="23" />
+ <bounds state="100" x="954" y="534" width="40" height="23" />
+ </element>
<element ref="chordvolume"><bounds x="878" y="558" width="139" height="13" /></element>
</group>
@@ -518,11 +559,21 @@ license:CC0
<element ref="slidermin"><bounds x="1047" y="522" width="136" height="13" /></element>
<element ref="slidermax"><bounds x="1047" y="522" width="136" height="13" /></element>
<element ref="slider"><bounds x="1057" y="534" width="116" height="22" /></element>
+ <element ref="slider-bar-yellow">
+ <animate inputtag="RYP4_3" mask="0xff" />
+ <bounds state="0" x="1057" y="534" width="40" height="23" />
+ <bounds state="100" x="1133" y="534" width="40" height="23" />
+ </element>
<element ref="volume"><bounds x="1057" y="558" width="116" height="13" /></element>
<element ref="sliderslow"><bounds x="1232" y="522" width="172" height="13" /></element>
<element ref="sliderfast"><bounds x="1232" y="522" width="172" height="13" /></element>
<element ref="slider-tempo"><bounds x="1242" y="534" width="152" height="22" /></element>
+ <element ref="slider-bar-yellow">
+ <animate inputtag="RYP4_4" mask="0xff" />
+ <bounds state="0" x="1242" y="534" width="40" height="23" />
+ <bounds state="100" x="1354" y="534" width="40" height="23" />
+ </element>
<element ref="tempo"><bounds x="1242" y="558" width="152" height="13" /></element>
</group>
@@ -617,6 +668,11 @@ license:CC0
<element ref="slidermin"><bounds x="1629" y="522" width="136" height="13" /></element>
<element ref="slidermax"><bounds x="1629" y="522" width="136" height="13" /></element>
<element ref="slider"><bounds x="1639" y="534" width="116" height="22" /></element>
+ <element ref="slider-bar-green">
+ <animate inputtag="RYP4_2" mask="0xff" />
+ <bounds state="0" x="1639" y="534" width="40" height="23" />
+ <bounds state="100" x="1715" y="534" width="40" height="23" />
+ </element>
<element ref="volume"><bounds x="1639" y="558" width="116" height="13" /></element>
<!-- right column -->
@@ -709,6 +765,11 @@ license:CC0
<element ref="slidermin"><bounds x="2029" y="522" width="136" height="13" /></element>
<element ref="slidermax"><bounds x="2029" y="522" width="136" height="13" /></element>
<element ref="slider"><bounds x="2038" y="534" width="116" height="22" /></element>
+ <element ref="slider-bar-grey">
+ <animate inputtag="RYP4_1" mask="0xff" />
+ <bounds state="0" x="2038" y="534" width="40" height="23" />
+ <bounds state="100" x="2114" y="534" width="40" height="23" />
+ </element>
<element ref="volume"><bounds x="2038" y="558" width="116" height="13" /></element>
<!-- right column -->
@@ -773,7 +834,7 @@ license:CC0
<element ref="keysplit"><bounds x="247" y="617" width="85" height="13" /></element>
<element ref="button-yellow" inputtag="DRVIF_3" inputmask="0x10"><bounds x="338" y="618" width="40" height="15" /></element>
- <element ref="led" name="DRVIF_3_DP4"><bounds x="381" y="619" width="12" height="12" /></element>
+ <element ref="led" name="DRVIF_2_DP4"><bounds x="381" y="619" width="12" height="12" /></element>
<element ref="keyboardpercussion"><bounds x="399" y="617" width="160" height="13" /></element>
<element ref="fillin"><bounds x="532" y="617" width="60" height="13" /></element>