summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/mame/audio/cinemat.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/mame/audio/cinemat.c')
-rw-r--r--trunk/src/mame/audio/cinemat.c1621
1 files changed, 1621 insertions, 0 deletions
diff --git a/trunk/src/mame/audio/cinemat.c b/trunk/src/mame/audio/cinemat.c
new file mode 100644
index 00000000000..64b29be3b4c
--- /dev/null
+++ b/trunk/src/mame/audio/cinemat.c
@@ -0,0 +1,1621 @@
+/***************************************************************************
+
+ Cinematronics vector hardware
+
+ Special thanks to Neil Bradley, Zonn Moore, and Jeff Mitchell of the
+ Retrocade Alliance
+
+ Update:
+ 6/27/99 Jim Hernandez -- 1st Attempt at Fixing Drone Star Castle sound and
+ pitch adjustments.
+ 6/30/99 MLR added Rip Off, Solar Quest, Armor Attack (no samples yet)
+ 11/04/08 Jim Hernandez -- Fixed Drone Star Castle sound again. It was
+ broken for a long time due to some changes.
+
+ Bugs: Sometimes the death explosion (small explosion) does not trigger.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "cpu/ccpu/ccpu.h"
+#include "cpu/z80/z80daisy.h"
+#include "machine/z80ctc.h"
+#include "includes/cinemat.h"
+#include "sound/samples.h"
+#include "sound/ay8910.h"
+
+
+/*************************************
+ *
+ * Macros
+ *
+ *************************************/
+
+#define RISING_EDGE(bit, changed, val) (((changed) & (bit)) && ((val) & (bit)))
+#define FALLING_EDGE(bit, changed, val) (((changed) & (bit)) && !((val) & (bit)))
+
+#define SOUNDVAL_RISING_EDGE(bit) RISING_EDGE(bit, bits_changed, sound_val)
+#define SOUNDVAL_FALLING_EDGE(bit) FALLING_EDGE(bit, bits_changed, sound_val)
+
+#define SHIFTREG_RISING_EDGE(bit) RISING_EDGE(bit, (state->m_last_shift ^ state->m_current_shift), state->m_current_shift)
+#define SHIFTREG_FALLING_EDGE(bit) FALLING_EDGE(bit, (state->m_last_shift ^ state->m_current_shift), state->m_current_shift)
+
+#define SHIFTREG2_RISING_EDGE(bit) RISING_EDGE(bit, (state->m_last_shift2 ^ state->m_current_shift), state->m_current_shift)
+#define SHIFTREG2_FALLING_EDGE(bit) FALLING_EDGE(bit, (state->m_last_shift2 ^ state->m_current_shift), state->m_current_shift)
+
+
+/*************************************
+ *
+ * Generic sound write
+ *
+ *************************************/
+
+WRITE8_MEMBER(cinemat_state::cinemat_sound_control_w)
+{
+ UINT8 oldval = m_sound_control;
+
+ /* form an 8-bit value with the new bit */
+ m_sound_control = (m_sound_control & ~(1 << offset)) | ((data & 1) << offset);
+
+ /* if something changed, call the sound subroutine */
+ if ((m_sound_control != oldval) && m_sound_handler)
+ (*m_sound_handler)(machine(), m_sound_control, m_sound_control ^ oldval);
+}
+
+
+
+/*************************************
+ *
+ * Generic sound init
+ *
+ *************************************/
+
+static MACHINE_START( generic )
+{
+ cinemat_state *state = machine.driver_data<cinemat_state>();
+ /* register for save states */
+ state_save_register_global(machine, state->m_sound_control);
+ state_save_register_global(machine, state->m_current_shift);
+ state_save_register_global(machine, state->m_last_shift);
+ state_save_register_global(machine, state->m_last_shift2);
+ state_save_register_global(machine, state->m_current_pitch);
+ state_save_register_global(machine, state->m_last_frame);
+ state_save_register_global_array(machine, state->m_sound_fifo);
+ state_save_register_global(machine, state->m_sound_fifo_in);
+ state_save_register_global(machine, state->m_sound_fifo_out);
+ state_save_register_global(machine, state->m_last_portb_write);
+}
+
+
+static void generic_init(running_machine &machine, void (*callback)(running_machine &,UINT8, UINT8))
+{
+ cinemat_state *state = machine.driver_data<cinemat_state>();
+ /* call the standard init */
+ MACHINE_RESET_CALL(cinemat);
+
+ /* set the sound handler */
+ state->m_sound_handler = callback;
+
+ /* reset sound control */
+ state->m_sound_control = 0x9f;
+
+ /* reset shift register values */
+ state->m_current_shift = 0xffff;
+ state->m_last_shift = 0xffff;
+ state->m_last_shift2 = 0xffff;
+
+ /* reset frame counters */
+ state->m_last_frame = 0;
+
+ /* reset Star Castle pitch */
+ state->m_current_pitch = 0x10000;
+}
+
+
+
+/*************************************
+ *
+ * Space Wars
+ *
+ *************************************/
+
+static const char *const spacewar_sample_names[] =
+{
+ "*spacewar",
+ "explode1",
+ "fire1",
+ "idle",
+ "thrust1",
+ "thrust2",
+ "pop",
+ "explode2",
+ "fire2",
+ 0
+};
+
+static const samples_interface spacewar_samples_interface =
+{
+ 8,
+ spacewar_sample_names
+};
+
+static void spacewar_sound_w(running_machine &machine, UINT8 sound_val, UINT8 bits_changed)
+{
+ samples_device *samples = machine.device<samples_device>("samples");
+
+ /* Explosion - rising edge */
+ if (SOUNDVAL_RISING_EDGE(0x01))
+ samples->start(0, (machine.rand() & 1) ? 0 : 6);
+
+ /* Fire sound - rising edge */
+ if (SOUNDVAL_RISING_EDGE(0x02))
+ samples->start(1, (machine.rand() & 1) ? 1 : 7);
+
+ /* Player 1 thrust - 0=on, 1=off */
+ if (SOUNDVAL_FALLING_EDGE(0x04))
+ samples->start(3, 3, true);
+ if (SOUNDVAL_RISING_EDGE(0x04))
+ samples->stop(3);
+
+ /* Player 2 thrust - 0=on, 1-off */
+ if (SOUNDVAL_FALLING_EDGE(0x08))
+ samples->start(4, 4, true);
+ if (SOUNDVAL_RISING_EDGE(0x08))
+ samples->stop(4);
+
+ /* Mute - 0=off, 1=on */
+ if (SOUNDVAL_FALLING_EDGE(0x10))
+ samples->start(2, 2, true); /* play idle sound */
+ if (SOUNDVAL_RISING_EDGE(0x10))
+ {
+ int i;
+
+ /* turn off all but the idle sound */
+ for (i = 0; i < 5; i++)
+ if (i != 2)
+ samples->stop(i);
+
+ /* Pop when board is shut off */
+ samples->start(2, 5);
+ }
+}
+
+static MACHINE_RESET( spacewar )
+{
+ generic_init(machine, spacewar_sound_w);
+}
+
+MACHINE_CONFIG_FRAGMENT( spacewar_sound )
+ MCFG_MACHINE_START(generic)
+ MCFG_MACHINE_RESET(spacewar)
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SAMPLES_ADD("samples", spacewar_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+
+
+/*************************************
+ *
+ * Barrier
+ *
+ *************************************/
+
+static const char *const barrier_sample_names[] =
+{
+ "*barrier",
+ "playrdie",
+ "playmove",
+ "enemmove",
+ 0
+};
+
+static const samples_interface barrier_samples_interface =
+{
+ 3,
+ barrier_sample_names
+};
+
+static void barrier_sound_w(running_machine &machine, UINT8 sound_val, UINT8 bits_changed)
+{
+ samples_device *samples = machine.device<samples_device>("samples");
+
+ /* Player die - rising edge */
+ if (SOUNDVAL_RISING_EDGE(0x01))
+ samples->start(0, 0);
+
+ /* Player move - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x02))
+ samples->start(1, 1);
+
+ /* Enemy move - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x04))
+ samples->start(2, 2);
+}
+
+static MACHINE_RESET( barrier )
+{
+ generic_init(machine, barrier_sound_w);
+}
+
+MACHINE_CONFIG_FRAGMENT( barrier_sound )
+ MCFG_MACHINE_START(generic)
+ MCFG_MACHINE_RESET(barrier)
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SAMPLES_ADD("samples", barrier_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+
+
+/*************************************
+ *
+ * Speed Freak
+ *
+ *************************************/
+
+static const char *const speedfrk_sample_names[] =
+{
+ "*speedfrk",
+ "offroad",
+ NULL
+};
+
+static const samples_interface speedfrk_samples_interface =
+{
+ 1,
+ speedfrk_sample_names
+};
+
+static void speedfrk_sound_w(running_machine &machine, UINT8 sound_val, UINT8 bits_changed)
+{
+ cinemat_state *state = machine.driver_data<cinemat_state>();
+ samples_device *samples = machine.device<samples_device>("samples");
+
+ /* on the falling edge of bit 0x08, clock the inverse of bit 0x04 into the top of the shiftreg */
+ if (SOUNDVAL_FALLING_EDGE(0x08))
+ {
+ state->m_current_shift = ((state->m_current_shift >> 1) & 0x7fff) | ((~sound_val << 13) & 1);
+ /* high 12 bits control the frequency - counts from value to $FFF, carry triggers */
+ /* another counter */
+
+ /* low 4 bits control the volume of the noise output (explosion?) */
+ }
+
+ /* off-road - 1=on, 0=off */
+ if (SOUNDVAL_RISING_EDGE(0x10))
+ samples->start(0, 0, true);
+ if (SOUNDVAL_FALLING_EDGE(0x10))
+ samples->stop(0);
+
+ /* start LED is controlled by bit 0x02 */
+ set_led_status(machine, 0, ~sound_val & 0x02);
+}
+
+static MACHINE_RESET( speedfrk )
+{
+ generic_init(machine, speedfrk_sound_w);
+}
+
+MACHINE_CONFIG_FRAGMENT( speedfrk_sound )
+ MCFG_MACHINE_START(generic)
+ MCFG_MACHINE_RESET(speedfrk)
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SAMPLES_ADD("samples", speedfrk_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+
+
+/*************************************
+ *
+ * Star Hawk
+ *
+ *************************************/
+
+static const char *const starhawk_sample_names[] =
+{
+ "*starhawk",
+ "explode",
+ "rlaser",
+ "llaser",
+ "k",
+ "master",
+ "kexit",
+ NULL
+};
+
+static const samples_interface starhawk_samples_interface =
+{
+ 5,
+ starhawk_sample_names
+};
+
+static void starhawk_sound_w(running_machine &machine, UINT8 sound_val, UINT8 bits_changed)
+{
+ samples_device *samples = machine.device<samples_device>("samples");
+
+ /* explosion - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x01))
+ samples->start(0, 0);
+
+ /* right laser - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x02))
+ samples->start(1, 1);
+
+ /* left laser - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x04))
+ samples->start(2, 2);
+
+ /* K - 0=on, 1=off */
+ if (SOUNDVAL_FALLING_EDGE(0x08))
+ samples->start(3, 3, true);
+ if (SOUNDVAL_RISING_EDGE(0x08))
+ samples->stop(3);
+
+ /* master - 0=on, 1=off */
+ if (SOUNDVAL_FALLING_EDGE(0x10))
+ samples->start(4, 4, true);
+ if (SOUNDVAL_RISING_EDGE(0x10))
+ samples->stop(4);
+
+ /* K exit - 1=on, 0=off */
+ if (SOUNDVAL_RISING_EDGE(0x80))
+ samples->start(3, 5, true);
+ if (SOUNDVAL_FALLING_EDGE(0x80))
+ samples->stop(3);
+}
+
+static MACHINE_RESET( starhawk )
+{
+ generic_init(machine, starhawk_sound_w);
+}
+
+MACHINE_CONFIG_FRAGMENT( starhawk_sound )
+ MCFG_MACHINE_START(generic)
+ MCFG_MACHINE_RESET(starhawk)
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SAMPLES_ADD("samples", starhawk_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+
+
+/*************************************
+ *
+ * Sundance
+ *
+ *************************************/
+
+static const char *const sundance_sample_names[] =
+{
+ "*sundance",
+ "bong",
+ "whoosh",
+ "explsion",
+ "ping1",
+ "ping2",
+ "hatch",
+ 0
+};
+
+static const samples_interface sundance_samples_interface =
+{
+ 6,
+ sundance_sample_names
+};
+
+static void sundance_sound_w(running_machine &machine, UINT8 sound_val, UINT8 bits_changed)
+{
+ samples_device *samples = machine.device<samples_device>("samples");
+
+ /* bong - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x01))
+ samples->start(0, 0);
+
+ /* whoosh - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x02))
+ samples->start(1, 1);
+
+ /* explosion - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x04))
+ samples->start(2, 2);
+
+ /* ping - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x08))
+ samples->start(3, 3);
+
+ /* ping - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x10))
+ samples->start(4, 4);
+
+ /* hatch - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x80))
+ samples->start(5, 5);
+}
+
+static MACHINE_RESET( sundance )
+{
+ generic_init(machine, sundance_sound_w);
+}
+
+MACHINE_CONFIG_FRAGMENT( sundance_sound )
+ MCFG_MACHINE_START(generic)
+ MCFG_MACHINE_RESET(sundance)
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SAMPLES_ADD("samples", sundance_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+
+
+/*************************************
+ *
+ * Tail Gunner
+ *
+ *************************************/
+
+static const char *const tailg_sample_names[] =
+{
+ "*tailg",
+ "sexplode",
+ "thrust1",
+ "slaser",
+ "shield",
+ "bounce",
+ "hypersp",
+ NULL
+};
+
+static const samples_interface tailg_samples_interface =
+{
+ 6,
+ tailg_sample_names
+};
+
+static void tailg_sound_w(running_machine &machine, UINT8 sound_val, UINT8 bits_changed)
+{
+ cinemat_state *state = machine.driver_data<cinemat_state>();
+ /* the falling edge of bit 0x10 clocks bit 0x08 into the mux selected by bits 0x07 */
+ if (SOUNDVAL_FALLING_EDGE(0x10))
+ {
+ samples_device *samples = machine.device<samples_device>("samples");
+
+ /* update the shift register (actually just a simple mux) */
+ state->m_current_shift = (state->m_current_shift & ~(1 << (sound_val & 7))) | (((sound_val >> 3) & 1) << (sound_val & 7));
+
+ /* explosion - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x01))
+ samples->start(0, 0);
+
+ /* rumble - 0=on, 1=off */
+ if (SHIFTREG_FALLING_EDGE(0x02))
+ samples->start(1, 1, true);
+ if (SHIFTREG_RISING_EDGE(0x02))
+ samples->stop(1);
+
+ /* laser - 0=on, 1=off */
+ if (SHIFTREG_FALLING_EDGE(0x04))
+ samples->start(2, 2, true);
+ if (SHIFTREG_RISING_EDGE(0x04))
+ samples->stop(2);
+
+ /* shield - 0=on, 1=off */
+ if (SHIFTREG_FALLING_EDGE(0x08))
+ samples->start(3, 3, true);
+ if (SHIFTREG_RISING_EDGE(0x08))
+ samples->stop(3);
+
+ /* bounce - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x10))
+ samples->start(4, 4);
+
+ /* hyperspace - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x20))
+ samples->start(5, 5);
+
+ /* LED */
+ set_led_status(machine, 0, state->m_current_shift & 0x40);
+
+ /* remember the previous value */
+ state->m_last_shift = state->m_current_shift;
+ }
+}
+
+static MACHINE_RESET( tailg )
+{
+ generic_init(machine, tailg_sound_w);
+}
+
+MACHINE_CONFIG_FRAGMENT( tailg_sound )
+ MCFG_MACHINE_START(generic)
+ MCFG_MACHINE_RESET(tailg)
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SAMPLES_ADD("samples", tailg_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+
+
+/*************************************
+ *
+ * Warrior
+ *
+ *************************************/
+
+static const char *const warrior_sample_names[] =
+{
+ "*warrior",
+ "bgmhum1",
+ "bgmhum2",
+ "killed",
+ "fall",
+ "appear",
+ NULL
+};
+
+static const samples_interface warrior_samples_interface =
+{
+ 5,
+ warrior_sample_names
+};
+
+static void warrior_sound_w(running_machine &machine, UINT8 sound_val, UINT8 bits_changed)
+{
+ samples_device *samples = machine.device<samples_device>("samples");
+
+ /* normal level - 0=on, 1=off */
+ if (SOUNDVAL_FALLING_EDGE(0x01))
+ samples->start(0, 0, true);
+ if (SOUNDVAL_RISING_EDGE(0x01))
+ samples->stop(0);
+
+ /* hi level - 0=on, 1=off */
+ if (SOUNDVAL_FALLING_EDGE(0x02))
+ samples->start(1, 1, true);
+ if (SOUNDVAL_RISING_EDGE(0x02))
+ samples->stop(1);
+
+ /* explosion - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x04))
+ samples->start(2, 2);
+
+ /* fall - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x08))
+ samples->start(3, 3);
+
+ /* appear - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x10))
+ samples->start(4, 4);
+}
+
+static MACHINE_RESET( warrior )
+{
+ generic_init(machine, warrior_sound_w);
+}
+
+MACHINE_CONFIG_FRAGMENT( warrior_sound )
+ MCFG_MACHINE_START(generic)
+ MCFG_MACHINE_RESET(warrior)
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SAMPLES_ADD("samples", warrior_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+
+
+/*************************************
+ *
+ * Armor Attack
+ *
+ *************************************/
+
+static const char *const armora_sample_names[] =
+{
+ "*armora",
+ "loexp",
+ "jeepfire",
+ "hiexp",
+ "tankfire",
+ "tankeng",
+ "beep",
+ "chopper",
+ NULL
+};
+
+static const samples_interface armora_samples_interface =
+{
+ 7,
+ armora_sample_names
+};
+
+static void armora_sound_w(running_machine &machine, UINT8 sound_val, UINT8 bits_changed)
+{
+ cinemat_state *state = machine.driver_data<cinemat_state>();
+ samples_device *samples = machine.device<samples_device>("samples");
+
+ /* on the rising edge of bit 0x10, clock bit 0x80 into the shift register */
+ if (SOUNDVAL_RISING_EDGE(0x10))
+ state->m_current_shift = ((state->m_current_shift >> 1) & 0x7f) | (sound_val & 0x80);
+
+ /* execute on the rising edge of bit 0x01 */
+ if (SOUNDVAL_RISING_EDGE(0x01))
+ {
+ /* bits 0-4 control the tank sound speed */
+
+ /* lo explosion - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x10))
+ samples->start(0, 0);
+
+ /* jeep fire - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x20))
+ samples->start(1, 1);
+
+ /* hi explosion - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x40))
+ samples->start(2, 2);
+
+ /* tank fire - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x80))
+ samples->start(3, 3);
+
+ /* remember the previous value */
+ state->m_last_shift = state->m_current_shift;
+ }
+
+ /* tank sound - 0=on, 1=off */
+ /* still not totally correct - should be multiple speeds based on remaining bits in shift reg */
+ if (SOUNDVAL_FALLING_EDGE(0x02))
+ samples->start(4, 4, true);
+ if (SOUNDVAL_RISING_EDGE(0x02))
+ samples->stop(4);
+
+ /* beep sound - 0=on, 1=off */
+ if (SOUNDVAL_FALLING_EDGE(0x04))
+ samples->start(5, 5, true);
+ if (SOUNDVAL_RISING_EDGE(0x04))
+ samples->stop(5);
+
+ /* chopper sound - 0=on, 1=off */
+ if (SOUNDVAL_FALLING_EDGE(0x08))
+ samples->start(6, 6, true);
+ if (SOUNDVAL_RISING_EDGE(0x08))
+ samples->stop(6);
+}
+
+static MACHINE_RESET( armora )
+{
+ generic_init(machine, armora_sound_w);
+}
+
+MACHINE_CONFIG_FRAGMENT( armora_sound )
+ MCFG_MACHINE_START(generic)
+ MCFG_MACHINE_RESET(armora)
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SAMPLES_ADD("samples", armora_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+
+
+/*************************************
+ *
+ * Ripoff
+ *
+ *************************************/
+
+static const char *const ripoff_sample_names[] =
+{
+ "*ripoff",
+ "bonuslvl",
+ "eattack",
+ "shipfire",
+ "efire",
+ "explosn",
+ "bg1",
+ "bg2",
+ "bg3",
+ "bg4",
+ "bg5",
+ "bg6",
+ "bg7",
+ "bg8",
+ NULL
+};
+
+static const samples_interface ripoff_samples_interface =
+{
+ 6,
+ ripoff_sample_names
+};
+
+static void ripoff_sound_w(running_machine &machine, UINT8 sound_val, UINT8 bits_changed)
+{
+ cinemat_state *state = machine.driver_data<cinemat_state>();
+ samples_device *samples = machine.device<samples_device>("samples");
+
+ /* on the rising edge of bit 0x02, clock bit 0x01 into the shift register */
+ if (SOUNDVAL_RISING_EDGE(0x02))
+ state->m_current_shift = ((state->m_current_shift >> 1) & 0x7f) | ((sound_val << 7) & 0x80);
+
+ /* execute on the rising edge of bit 0x04 */
+ if (SOUNDVAL_RISING_EDGE(0x04))
+ {
+ /* background - 0=on, 1=off, selected by bits 0x38 */
+ if ((((state->m_current_shift ^ state->m_last_shift) & 0x38) && !(state->m_current_shift & 0x04)) || SHIFTREG_FALLING_EDGE(0x04))
+ samples->start(5, 5 + ((state->m_current_shift >> 5) & 7), true);
+ if (SHIFTREG_RISING_EDGE(0x04))
+ samples->stop(5);
+
+ /* beep - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x02))
+ samples->start(0, 0);
+
+ /* motor - 0=on, 1=off */
+ if (SHIFTREG_FALLING_EDGE(0x01))
+ samples->start(1, 1, true);
+ if (SHIFTREG_RISING_EDGE(0x01))
+ samples->stop(1);
+
+ /* remember the previous value */
+ state->m_last_shift = state->m_current_shift;
+ }
+
+ /* torpedo - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x08))
+ samples->start(2, 2);
+
+ /* laser - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x10))
+ samples->start(3, 3);
+
+ /* explosion - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x80))
+ samples->start(4, 4);
+}
+
+static MACHINE_RESET( ripoff )
+{
+ generic_init(machine, ripoff_sound_w);
+}
+
+MACHINE_CONFIG_FRAGMENT( ripoff_sound )
+ MCFG_MACHINE_START(generic)
+ MCFG_MACHINE_RESET(ripoff)
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SAMPLES_ADD("samples", ripoff_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+
+
+/*************************************
+ *
+ * Star Castle
+ *
+ *************************************/
+
+static const char *const starcas_sample_names[] =
+{
+ "*starcas",
+ "cfire",
+ "shield",
+ "star",
+ "thrust",
+ "drone",
+ "lexplode",
+ "sexplode",
+ "pfire",
+ 0
+};
+
+static const samples_interface starcas_samples_interface =
+{
+ 8,
+ starcas_sample_names
+};
+
+static void starcas_sound_w(running_machine &machine, UINT8 sound_val, UINT8 bits_changed)
+{
+ cinemat_state *state = machine.driver_data<cinemat_state>();
+ samples_device *samples = machine.device<samples_device>("samples");
+ UINT32 target_pitch;
+
+ /* on the rising edge of bit 0x10, clock bit 0x80 into the shift register */
+ if (SOUNDVAL_RISING_EDGE(0x10))
+ state->m_current_shift = ((state->m_current_shift >> 1) & 0x7f) | (sound_val & 0x80);
+
+ /* execute on the rising edge of bit 0x01 */
+ if (SOUNDVAL_RISING_EDGE(0x01))
+ {
+ /* fireball - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x80))
+ samples->start(0, 0);
+
+ /* shield hit - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x40))
+ samples->start(1, 1);
+
+ /* star sound - 0=off, 1=on */
+ if (SHIFTREG_RISING_EDGE(0x20))
+ samples->start(2, 2, true);
+ if (SHIFTREG_FALLING_EDGE(0x20))
+ samples->stop(2);
+
+ /* thrust sound - 1=off, 0=on*/
+ if (SHIFTREG_FALLING_EDGE(0x10))
+ samples->start(3, 3, true);
+ if (SHIFTREG_RISING_EDGE(0x10))
+ samples->stop(3);
+
+ /* drone - 1=off, 0=on */
+ if (SHIFTREG_FALLING_EDGE(0x08))
+ samples->start(4, 4, true);
+ if (SHIFTREG_RISING_EDGE(0x08))
+ samples->stop(4);
+
+ /* latch the drone pitch */
+ target_pitch = (state->m_current_shift & 7) + ((state->m_current_shift & 2) << 2);
+ target_pitch = 0x5800 + (target_pitch << 12);
+
+ /* once per frame slide the pitch toward the target */
+ if (machine.primary_screen->frame_number() > state->m_last_frame)
+ {
+ if (state->m_current_pitch > target_pitch)
+ state->m_current_pitch -= 225;
+ if (state->m_current_pitch < target_pitch)
+ state->m_current_pitch += 150;
+ samples->set_frequency(4, state->m_current_pitch);
+ state->m_last_frame = machine.primary_screen->frame_number();
+ }
+
+ /* remember the previous value */
+ state->m_last_shift = state->m_current_shift;
+ }
+
+ /* loud explosion - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x02))
+ samples->start(5, 5);
+
+ /* soft explosion - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x04))
+ samples->start(6, 6);
+
+ /* player fire - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x08))
+ samples->start(7, 7);
+}
+
+static MACHINE_RESET( starcas )
+{
+ generic_init(machine, starcas_sound_w);
+}
+
+MACHINE_CONFIG_FRAGMENT( starcas_sound )
+ MCFG_MACHINE_START(generic)
+ MCFG_MACHINE_RESET(starcas)
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SAMPLES_ADD("samples", starcas_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.5)
+MACHINE_CONFIG_END
+
+
+
+/*************************************
+ *
+ * Solar Quest
+ *
+ *************************************/
+
+static const char *const solarq_sample_names[] =
+{
+ "*solarq",
+ "bigexpl",
+ "smexpl",
+ "lthrust",
+ "slaser",
+ "pickup",
+ "nuke2",
+ "nuke1",
+ "music",
+ NULL
+};
+
+static const samples_interface solarq_samples_interface =
+{
+ 8,
+ solarq_sample_names
+};
+
+static void solarq_sound_w(running_machine &machine, UINT8 sound_val, UINT8 bits_changed)
+{
+ cinemat_state *state = machine.driver_data<cinemat_state>();
+ samples_device *samples = machine.device<samples_device>("samples");
+
+ /* on the rising edge of bit 0x10, clock bit 0x80 into the shift register */
+ if (SOUNDVAL_RISING_EDGE(0x10))
+ state->m_current_shift = ((state->m_current_shift >> 1) & 0x7fff) | ((sound_val << 8) & 0x8000);
+
+ /* execute on the rising edge of bit 0x02 */
+ if (SOUNDVAL_RISING_EDGE(0x02))
+ {
+ /* only the upper 8 bits matter */
+ state->m_current_shift >>= 8;
+
+ /* loud explosion - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x80))
+ samples->start(0, 0);
+
+ /* soft explosion - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x40))
+ samples->start(1, 1);
+
+ /* thrust - 0=on, 1=off */
+ if (SHIFTREG_FALLING_EDGE(0x20))
+ {
+ state->m_target_volume = 1.0;
+ if (!samples->playing(2))
+ samples->start(2, 2, true);
+ }
+ if (SHIFTREG_RISING_EDGE(0x20))
+ state->m_target_volume = 0;
+
+ /* ramp the thrust volume */
+ if (samples->playing(2) && machine.primary_screen->frame_number() > state->m_last_frame)
+ {
+ if (state->m_current_volume > state->m_target_volume)
+ state->m_current_volume -= 0.078f;
+ if (state->m_current_volume < state->m_target_volume)
+ state->m_current_volume += 0.078f;
+ if (state->m_current_volume > 0)
+ samples->set_volume(2, state->m_current_volume);
+ else
+ samples->stop(2);
+ state->m_last_frame = machine.primary_screen->frame_number();
+ }
+
+ /* fire - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x10))
+ samples->start(3, 3);
+
+ /* capture - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x08))
+ samples->start(4, 4);
+
+ /* nuke - 1=on, 0=off */
+ if (SHIFTREG_RISING_EDGE(0x04))
+ samples->start(5, 5, true);
+ if (SHIFTREG_FALLING_EDGE(0x04))
+ samples->stop(5);
+
+ /* photon - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x02))
+ samples->start(6, 6);
+
+ /* remember the previous value */
+ state->m_last_shift = state->m_current_shift;
+ }
+
+ /* clock music data on the rising edge of bit 0x01 */
+ if (SOUNDVAL_RISING_EDGE(0x01))
+ {
+ int freq, vol;
+
+ /* start/stop the music sample on the high bit */
+ if (SHIFTREG2_RISING_EDGE(0x8000))
+ samples->start(7, 7, true);
+ if (SHIFTREG2_FALLING_EDGE(0x8000))
+ samples->stop(7);
+
+ /* set the frequency */
+ freq = 56818.181818 / (4096 - (state->m_current_shift & 0xfff));
+ samples->set_frequency(7, 44100 * freq / 1050);
+
+ /* set the volume */
+ vol = (~state->m_current_shift >> 12) & 7;
+ samples->set_volume(7, vol / 7.0);
+
+ /* remember the previous value */
+ state->m_last_shift2 = state->m_current_shift;
+ }
+}
+
+static MACHINE_RESET( solarq )
+{
+ generic_init(machine, solarq_sound_w);
+}
+
+MACHINE_CONFIG_FRAGMENT( solarq_sound )
+ MCFG_MACHINE_START(generic)
+ MCFG_MACHINE_RESET(solarq)
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SAMPLES_ADD("samples", solarq_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.5)
+MACHINE_CONFIG_END
+
+
+
+/*************************************
+ *
+ * Boxing Bugs
+ *
+ *************************************/
+
+static const char *const boxingb_sample_names[] =
+{
+ "*boxingb",
+ "softexpl",
+ "loudexpl",
+ "chirp",
+ "eggcrack",
+ "bugpusha",
+ "bugpushb",
+ "bugdie",
+ "beetle",
+ "music",
+ "cannon",
+ "bounce",
+ "bell",
+ NULL
+};
+
+static const samples_interface boxingb_samples_interface =
+{
+ 12,
+ boxingb_sample_names
+};
+
+static void boxingb_sound_w(running_machine &machine, UINT8 sound_val, UINT8 bits_changed)
+{
+ cinemat_state *state = machine.driver_data<cinemat_state>();
+ samples_device *samples = machine.device<samples_device>("samples");
+
+ /* on the rising edge of bit 0x10, clock bit 0x80 into the shift register */
+ if (SOUNDVAL_RISING_EDGE(0x10))
+ state->m_current_shift = ((state->m_current_shift >> 1) & 0x7fff) | ((sound_val << 8) & 0x8000);
+
+ /* execute on the rising edge of bit 0x02 */
+ if (SOUNDVAL_RISING_EDGE(0x02))
+ {
+ /* only the upper 8 bits matter */
+ state->m_current_shift >>= 8;
+
+ /* soft explosion - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x80))
+ samples->start(0, 0);
+
+ /* loud explosion - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x40))
+ samples->start(1, 1);
+
+ /* chirping birds - 0=on, 1=off */
+ if (SHIFTREG_FALLING_EDGE(0x20))
+ samples->start(2, 2);
+ if (SHIFTREG_RISING_EDGE(0x20))
+ samples->stop(2);
+
+ /* egg cracking - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x10))
+ samples->start(3, 3);
+
+ /* bug pushing A - rising edge */
+ if (SHIFTREG_RISING_EDGE(0x08))
+ samples->start(4, 4);
+
+ /* bug pushing B - rising edge */
+ if (SHIFTREG_RISING_EDGE(0x04))
+ samples->start(5, 5);
+
+ /* bug dying - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x02))
+ samples->start(6, 6);
+
+ /* beetle on screen - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x01))
+ samples->start(7, 7);
+
+ /* remember the previous value */
+ state->m_last_shift = state->m_current_shift;
+ }
+
+ /* clock music data on the rising edge of bit 0x01 */
+ if (SOUNDVAL_RISING_EDGE(0x01))
+ {
+ int freq, vol;
+
+ /* start/stop the music sample on the high bit */
+ if (SHIFTREG2_RISING_EDGE(0x8000))
+ samples->start(8, 8, true);
+ if (SHIFTREG2_FALLING_EDGE(0x8000))
+ samples->stop(8);
+
+ /* set the frequency */
+ freq = 56818.181818 / (4096 - (state->m_current_shift & 0xfff));
+ samples->set_frequency(8, 44100 * freq / 1050);
+
+ /* set the volume */
+ vol = (~state->m_current_shift >> 12) & 3;
+ samples->set_volume(8, vol / 3.0);
+
+ /* cannon - falling edge */
+ if (SHIFTREG2_RISING_EDGE(0x4000))
+ samples->start(9, 9);
+
+ /* remember the previous value */
+ state->m_last_shift2 = state->m_current_shift;
+ }
+
+ /* bounce - rising edge */
+ if (SOUNDVAL_RISING_EDGE(0x04))
+ samples->start(10, 10);
+
+ /* bell - falling edge */
+ if (SOUNDVAL_RISING_EDGE(0x08))
+ samples->start(11, 11);
+}
+
+static MACHINE_RESET( boxingb )
+{
+ generic_init(machine, boxingb_sound_w);
+}
+
+MACHINE_CONFIG_FRAGMENT( boxingb_sound )
+ MCFG_MACHINE_START(generic)
+ MCFG_MACHINE_RESET(boxingb)
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SAMPLES_ADD("samples", boxingb_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+
+
+/*************************************
+ *
+ * War of the Worlds (B&W)
+ *
+ *************************************/
+
+static const char *const wotw_sample_names[] =
+{
+ "*wotw",
+ "cfire",
+ "shield",
+ "star",
+ "thrust",
+ "drone",
+ "lexplode",
+ "sexplode",
+ "pfire",
+ 0
+};
+
+static const samples_interface wotw_samples_interface =
+{
+ 8,
+ wotw_sample_names
+};
+
+static void wotw_sound_w(running_machine &machine, UINT8 sound_val, UINT8 bits_changed)
+{
+ cinemat_state *state = machine.driver_data<cinemat_state>();
+ samples_device *samples = machine.device<samples_device>("samples");
+ UINT32 target_pitch;
+
+ /* on the rising edge of bit 0x10, clock bit 0x80 into the shift register */
+ if (SOUNDVAL_RISING_EDGE(0x10))
+ state->m_current_shift = ((state->m_current_shift >> 1) & 0x7f) | (sound_val & 0x80);
+
+ /* execute on the rising edge of bit 0x01 */
+ if (SOUNDVAL_RISING_EDGE(0x01))
+ {
+ /* fireball - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x80))
+ samples->start(0, 0);
+
+ /* shield hit - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x40))
+ samples->start(1, 1);
+
+ /* star sound - 0=off, 1=on */
+ if (SHIFTREG_RISING_EDGE(0x20))
+ samples->start(2, 2, true);
+ if (SHIFTREG_FALLING_EDGE(0x20))
+ samples->stop(2);
+
+ /* thrust sound - 1=off, 0=on*/
+ if (SHIFTREG_FALLING_EDGE(0x10))
+ samples->start(3, 3, true);
+ if (SHIFTREG_RISING_EDGE(0x10))
+ samples->stop(3);
+
+ /* drone - 1=off, 0=on */
+ if (SHIFTREG_FALLING_EDGE(0x08))
+ samples->start(4, 4, true);
+ if (SHIFTREG_RISING_EDGE(0x08))
+ samples->stop(4);
+
+ /* latch the drone pitch */
+ target_pitch = (state->m_current_shift & 7) + ((state->m_current_shift & 2) << 2);
+ target_pitch = 0x10000 + (target_pitch << 12);
+
+ /* once per frame slide the pitch toward the target */
+ if (machine.primary_screen->frame_number() > state->m_last_frame)
+ {
+ if (state->m_current_pitch > target_pitch)
+ state->m_current_pitch -= 300;
+ if (state->m_current_pitch < target_pitch)
+ state->m_current_pitch += 200;
+ samples->set_frequency(4, state->m_current_pitch);
+ state->m_last_frame = machine.primary_screen->frame_number();
+ }
+
+ /* remember the previous value */
+ state->m_last_shift = state->m_current_shift;
+ }
+
+ /* loud explosion - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x02))
+ samples->start(5, 5);
+
+ /* soft explosion - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x04))
+ samples->start(6, 6);
+
+ /* player fire - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x08))
+ samples->start(7, 7);
+}
+
+static MACHINE_RESET( wotw )
+{
+ generic_init(machine, wotw_sound_w);
+}
+
+MACHINE_CONFIG_FRAGMENT( wotw_sound )
+ MCFG_MACHINE_START(generic)
+ MCFG_MACHINE_RESET(wotw)
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SAMPLES_ADD("samples", wotw_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+
+
+/*************************************
+ *
+ * War of the Worlds (color)
+ *
+ *************************************/
+
+static const char *const wotwc_sample_names[] =
+{
+ "*wotwc",
+ "cfire",
+ "shield",
+ "star",
+ "thrust",
+ "drone",
+ "lexplode",
+ "sexplode",
+ "pfire",
+ 0
+};
+
+static const samples_interface wotwc_samples_interface =
+{
+ 8,
+ wotwc_sample_names
+};
+
+static void wotwc_sound_w(running_machine &machine, UINT8 sound_val, UINT8 bits_changed)
+{
+ cinemat_state *state = machine.driver_data<cinemat_state>();
+ samples_device *samples = machine.device<samples_device>("samples");
+ UINT32 target_pitch;
+
+ /* on the rising edge of bit 0x10, clock bit 0x80 into the shift register */
+ if (SOUNDVAL_RISING_EDGE(0x10))
+ state->m_current_shift = ((state->m_current_shift >> 1) & 0x7f) | (sound_val & 0x80);
+
+ /* execute on the rising edge of bit 0x01 */
+ if (SOUNDVAL_RISING_EDGE(0x01))
+ {
+ /* fireball - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x80))
+ samples->start(0, 0);
+
+ /* shield hit - falling edge */
+ if (SHIFTREG_FALLING_EDGE(0x40))
+ samples->start(1, 1);
+
+ /* star sound - 0=off, 1=on */
+ if (SHIFTREG_RISING_EDGE(0x20))
+ samples->start(2, 2, true);
+ if (SHIFTREG_FALLING_EDGE(0x20))
+ samples->stop(2);
+
+ /* thrust sound - 1=off, 0=on*/
+ if (SHIFTREG_FALLING_EDGE(0x10))
+ samples->start(3, 3, true);
+ if (SHIFTREG_RISING_EDGE(0x10))
+ samples->stop(3);
+
+ /* drone - 1=off, 0=on */
+ if (SHIFTREG_FALLING_EDGE(0x08))
+ samples->start(4, 4, true);
+ if (SHIFTREG_RISING_EDGE(0x08))
+ samples->stop(4);
+
+ /* latch the drone pitch */
+ target_pitch = (state->m_current_shift & 7) + ((state->m_current_shift & 2) << 2);
+ target_pitch = 0x10000 + (target_pitch << 12);
+
+ /* once per frame slide the pitch toward the target */
+ if (machine.primary_screen->frame_number() > state->m_last_frame)
+ {
+ if (state->m_current_pitch > target_pitch)
+ state->m_current_pitch -= 300;
+ if (state->m_current_pitch < target_pitch)
+ state->m_current_pitch += 200;
+ samples->set_frequency(4, state->m_current_pitch);
+ state->m_last_frame = machine.primary_screen->frame_number();
+ }
+
+ /* remember the previous value */
+ state->m_last_shift = state->m_current_shift;
+ }
+
+ /* loud explosion - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x02))
+ samples->start(5, 5);
+
+ /* soft explosion - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x04))
+ samples->start(6, 6);
+
+ /* player fire - falling edge */
+ if (SOUNDVAL_FALLING_EDGE(0x08))
+ samples->start(7, 7);
+}
+
+static MACHINE_RESET( wotwc )
+{
+ generic_init(machine, wotwc_sound_w);
+}
+
+MACHINE_CONFIG_FRAGMENT( wotwc_sound )
+ MCFG_MACHINE_START(generic)
+ MCFG_MACHINE_RESET(wotwc)
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SAMPLES_ADD("samples", wotwc_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+
+
+/*************************************
+ *
+ * Demon
+ *
+ *************************************/
+
+static TIMER_CALLBACK( synced_sound_w )
+{
+ cinemat_state *state = machine.driver_data<cinemat_state>();
+ state->m_sound_fifo[state->m_sound_fifo_in] = param;
+ state->m_sound_fifo_in = (state->m_sound_fifo_in + 1) % 16;
+}
+
+
+static void demon_sound_w(running_machine &machine, UINT8 sound_val, UINT8 bits_changed)
+{
+ /* all inputs are inverted */
+ sound_val = ~sound_val;
+
+ /* watch for a 0->1 edge on bit 4 ("shift in") to clock in the new data */
+ if ((bits_changed & 0x10) && (sound_val & 0x10))
+ machine.scheduler().synchronize(FUNC(synced_sound_w), sound_val & 0x0f);
+}
+
+
+static READ8_DEVICE_HANDLER( sound_porta_r )
+{
+ cinemat_state *state = device->machine().driver_data<cinemat_state>();
+ /* bits 0-3 are the sound data; bit 4 is the data ready */
+ return state->m_sound_fifo[state->m_sound_fifo_out] | ((state->m_sound_fifo_in != state->m_sound_fifo_out) << 4);
+}
+
+
+static READ8_DEVICE_HANDLER( sound_portb_r )
+{
+ cinemat_state *state = device->machine().driver_data<cinemat_state>();
+ return state->m_last_portb_write;
+}
+
+
+static WRITE8_DEVICE_HANDLER( sound_portb_w )
+{
+ cinemat_state *state = device->machine().driver_data<cinemat_state>();
+ /* watch for a 0->1 edge on bit 0 ("shift out") to advance the data pointer */
+ if ((data & 1) != (state->m_last_portb_write & 1) && (data & 1) != 0)
+ state->m_sound_fifo_out = (state->m_sound_fifo_out + 1) % 16;
+
+ /* watch for a 0->1 edge of bit 1 ("hard reset") to reset the FIFO */
+ if ((data & 2) != (state->m_last_portb_write & 2) && (data & 2) != 0)
+ state->m_sound_fifo_in = state->m_sound_fifo_out = 0;
+
+ /* bit 2 controls the global mute */
+ if ((data & 4) != (state->m_last_portb_write & 4))
+ device->machine().sound().system_mute(data & 4);
+
+ /* remember the last value written */
+ state->m_last_portb_write = data;
+}
+
+
+static WRITE8_DEVICE_HANDLER( sound_output_w )
+{
+ logerror("sound_output = %02X\n", data);
+}
+
+
+static const ay8910_interface demon_ay8910_interface_1 =
+{
+ AY8910_LEGACY_OUTPUT,
+ AY8910_DEFAULT_LOADS,
+ DEVCB_HANDLER(sound_porta_r),
+ DEVCB_HANDLER(sound_portb_r),
+ DEVCB_NULL,
+ DEVCB_HANDLER(sound_portb_w)
+};
+
+static const ay8910_interface demon_ay8910_interface_3 =
+{
+ AY8910_LEGACY_OUTPUT,
+ AY8910_DEFAULT_LOADS,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(sound_output_w)
+};
+
+
+static Z80CTC_INTERFACE( demon_z80ctc_interface )
+{
+ 0, /* timer disables */
+ DEVCB_CPU_INPUT_LINE("audiocpu", INPUT_LINE_IRQ0), /* interrupt handler */
+ DEVCB_NULL, /* ZC/TO0 callback */
+ DEVCB_NULL, /* ZC/TO1 callback */
+ DEVCB_NULL /* ZC/TO2 callback */
+};
+
+
+static MACHINE_RESET( demon_sound )
+{
+ cinemat_state *state = machine.driver_data<cinemat_state>();
+ /* generic init */
+ generic_init(machine, demon_sound_w);
+
+ /* reset the FIFO */
+ state->m_sound_fifo_in = state->m_sound_fifo_out = 0;
+ state->m_last_portb_write = 0xff;
+
+ /* turn off channel A on AY8910 #0 because it is used as a low-pass filter */
+ ay8910_set_volume(machine.device("ay1"), 0, 0);
+}
+
+
+static ADDRESS_MAP_START( demon_sound_map, AS_PROGRAM, 8, driver_device )
+ AM_RANGE(0x0000, 0x1fff) AM_ROM
+ AM_RANGE(0x3000, 0x33ff) AM_RAM
+ AM_RANGE(0x4000, 0x4001) AM_DEVREAD_LEGACY("ay1", ay8910_r)
+ AM_RANGE(0x4002, 0x4003) AM_DEVWRITE_LEGACY("ay1", ay8910_data_address_w)
+ AM_RANGE(0x5000, 0x5001) AM_DEVREAD_LEGACY("ay2", ay8910_r)
+ AM_RANGE(0x5002, 0x5003) AM_DEVWRITE_LEGACY("ay2", ay8910_data_address_w)
+ AM_RANGE(0x6000, 0x6001) AM_DEVREAD_LEGACY("ay3", ay8910_r)
+ AM_RANGE(0x6002, 0x6003) AM_DEVWRITE_LEGACY("ay3", ay8910_data_address_w)
+ AM_RANGE(0x7000, 0x7000) AM_WRITENOP /* watchdog? */
+ADDRESS_MAP_END
+
+
+static ADDRESS_MAP_START( demon_sound_ports, AS_IO, 8, driver_device )
+ ADDRESS_MAP_GLOBAL_MASK(0xff)
+ AM_RANGE(0x00, 0x03) AM_DEVWRITE_LEGACY("ctc", z80ctc_w)
+ AM_RANGE(0x1c, 0x1f) AM_DEVWRITE_LEGACY("ctc", z80ctc_w)
+ADDRESS_MAP_END
+
+
+static const z80_daisy_config daisy_chain[] =
+{
+ { "ctc" },
+ { NULL }
+};
+
+
+MACHINE_CONFIG_FRAGMENT( demon_sound )
+
+ /* basic machine hardware */
+ MCFG_CPU_ADD("audiocpu", Z80, 3579545)
+ MCFG_CPU_CONFIG(daisy_chain)
+ MCFG_CPU_PROGRAM_MAP(demon_sound_map)
+ MCFG_CPU_IO_MAP(demon_sound_ports)
+
+ MCFG_Z80CTC_ADD("ctc", 3579545 /* same as "audiocpu" */, demon_z80ctc_interface)
+
+ MCFG_MACHINE_START(generic)
+ MCFG_MACHINE_RESET(demon_sound)
+
+ /* sound hardware */
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SOUND_ADD("ay1", AY8910, 3579545)
+ MCFG_SOUND_CONFIG(demon_ay8910_interface_1)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+
+ MCFG_SOUND_ADD("ay2", AY8910, 3579545)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+
+ MCFG_SOUND_ADD("ay3", AY8910, 3579545)
+ MCFG_SOUND_CONFIG(demon_ay8910_interface_3)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+MACHINE_CONFIG_END
+
+
+
+/*************************************
+ *
+ * QB3
+ *
+ *************************************/
+
+WRITE8_MEMBER(cinemat_state::qb3_sound_w)
+{
+ UINT16 rega = cpu_get_reg(machine().device("maincpu"), CCPU_A);
+ demon_sound_w(machine(), 0x00 | (~rega & 0x0f), 0x10);
+}
+
+
+static MACHINE_RESET( qb3_sound )
+{
+ cinemat_state *state = machine.driver_data<cinemat_state>();
+ MACHINE_RESET_CALL(demon_sound);
+ machine.device("maincpu")->memory().space(AS_IO)->install_write_handler(0x04, 0x04, write8_delegate(FUNC(cinemat_state::qb3_sound_w),state));
+
+ /* this patch prevents the sound ROM from eating itself when command $0A is sent */
+ /* on a cube rotate */
+ state->memregion("audiocpu")->base()[0x11dc] = 0x09;
+}
+
+
+MACHINE_CONFIG_DERIVED( qb3_sound, demon_sound )
+ MCFG_MACHINE_RESET(qb3_sound)
+MACHINE_CONFIG_END