// license:BSD-3-Clause
// copyright-holders:Zsolt Vasvari, hap
/*
* Carnival audio routines
*/
#include "emu.h"
#include "includes/vicdual.h"
/* output port 0x01 definitions - sound effect drive outputs */
#define OUT_PORT_1_RIFLE 0x01
#define OUT_PORT_1_CLANG 0x02
#define OUT_PORT_1_DUCK1 0x04
#define OUT_PORT_1_DUCK2 0x08
#define OUT_PORT_1_DUCK3 0x10
#define OUT_PORT_1_PIPEHIT 0x20
#define OUT_PORT_1_BONUS1 0x40
#define OUT_PORT_1_BONUS2 0x80
/* output port 0x02 definitions - sound effect drive outputs */
#define OUT_PORT_2_BEAR 0x04
#define OUT_PORT_2_RANKING 0x20
#define PLAY(samp,id,loop) samp->start( id, id, loop )
#define STOP(samp,id) samp->stop( id )
/* sample file names */
static const char *const carnival_sample_names[] =
{
"*carnival",
"bear",
"bonus1",
"bonus2",
"clang",
"duck1",
"duck2",
"duck3",
"pipehit",
"ranking",
"rifle",
nullptr
};
/* sample IDs - must match sample file name table above */
enum
{
SND_BEAR = 0,
SND_BONUS1,
SND_BONUS2,
SND_CLANG,
SND_DUCK1,
SND_DUCK2,
SND_DUCK3,
SND_PIPEHIT,
SND_RANKING,
SND_RIFLE
};
void carnival_state::carnival_audio_1_w(uint8_t data)
{
int bitsChanged;
int bitsGoneHigh;
int bitsGoneLow;
bitsChanged = m_port1State ^ data;
bitsGoneHigh = bitsChanged & data;
bitsGoneLow = bitsChanged & ~data;
m_port1State = data;
if ( bitsGoneLow & OUT_PORT_1_RIFLE )
{
PLAY( m_samples, SND_RIFLE, 0 );
}
if ( bitsGoneLow & OUT_PORT_1_CLANG )
{
PLAY( m_samples, SND_CLANG, 0 );
}
if ( bitsGoneLow & OUT_PORT_1_DUCK1 )
{
PLAY( m_samples, SND_DUCK1, 1 );
}
if ( bitsGoneHigh & OUT_PORT_1_DUCK1 )
{
STOP( m_samples, SND_DUCK1 );
}
if ( bitsGoneLow & OUT_PORT_1_DUCK2 )
{
PLAY( m_samples, SND_DUCK2, 1 );
}
if ( bitsGoneHigh & OUT_PORT_1_DUCK2 )
{
STOP( m_samples, SND_DUCK2 );
}
if ( bitsGoneLow & OUT_PORT_1_DUCK3 )
{
PLAY( m_samples, SND_DUCK3, 1 );
}
if ( bitsGoneHigh & OUT_PORT_1_DUCK3 )
{
STOP( m_samples, SND_DUCK3 );
}
if ( bitsGoneLow & OUT_PORT_1_PIPEHIT )
{
PLAY( m_samples, SND_PIPEHIT, 0 );
}
if ( bitsGoneLow & OUT_PORT_1_BONUS1 )
{
PLAY( m_samples, SND_BONUS1, 0 );
}
if ( bitsGoneLow & OUT_PORT_1_BONUS2 )
{
PLAY( m_samples, SND_BONUS2, 0 );
}
}
void carnival_state::carnival_audio_2_w(uint8_t data)
{
int bitsChanged;
//int bitsGoneHigh;
int bitsGoneLow;
bitsChanged = m_port2State ^ data;
//bitsGoneHigh = bitsChanged & data;
bitsGoneLow = bitsChanged & ~data;
m_port2State = data;
if ( bitsGoneLow & OUT_PORT_2_BEAR )
{
PLAY( m_samples, SND_BEAR, 0 );
}
if ( bitsGoneLow & OUT_PORT_2_RANKING )
{
PLAY( m_samples, SND_RANKING, 0 );
}
// d4: music board MCU reset
m_audiocpu->set_input_line(INPUT_LINE_RESET, (data & 0x10) ? CLEAR_LINE : ASSERT_LINE);
}
/* Music board */
// common
void carnival_state::mboard_map(address_map &map)
{
map(0x0000, 0x03ff).rom();
}
READ_LINE_MEMBER( carnival_state::carnival_music_port_t1_r )
{
// T1: comms from audio port 2 d3
return ~m_port2State >> 3 & 1;
}
// AY8912 music
void carnival_state::carnival_psg_latch()
{
if (m_musicBus & 1)
{
// BDIR W, BC1 selects address or data
if (m_musicBus & 2)
m_psg->address_w(m_musicData);
else
m_psg->data_w(m_musicData);
}
}
void carnival_state::carnivala_music_port_1_w(uint8_t data)
{
// P1: AY8912 d0-d7
m_musicData = data;
carnival_psg_latch();
}
void carnival_state::carnivala_music_port_2_w(uint8_t data)
{
// P2 d6: AY8912 BDIR(R/W)
// P2 d7: AY8912 BC1
m_musicBus = data >> 6 & 3;
carnival_psg_latch();
}
void carnival_state::carnivala_audio(machine_config &config)
{
/* music board */
I8035(config, m_audiocpu, XTAL(3'579'545));
m_audiocpu->set_addrmap(AS_PROGRAM, &carnival_state::mboard_map);
m_audiocpu->p1_out_cb().set(FUNC(carnival_state::carnivala_music_port_1_w));
m_audiocpu->p2_out_cb().set(FUNC(carnival_state::carnivala_music_port_2_w));
m_audiocpu->t1_in_cb().set(FUNC(carnival_state::carnival_music_port_t1_r));
AY8912(config, m_psg, XTAL(3'579'545)/3).add_route(ALL_OUTPUTS, "mono", 0.25); // also seen with AY-3-8910, daughterboard has place for either chip
/* samples */
SAMPLES(config, m_samples);
m_samples->set_channels(10);
m_samples->set_samples_names(carnival_sample_names);
m_samples->add_route(ALL_OUTPUTS, "mono", 0.5);
}
// PIT8253 music
void carnival_state::carnivalb_music_port_1_w(uint8_t data)
{
// P1: PIT8253 d0-d7
m_musicData = data;
}
void carnival_state::carnivalb_music_port_2_w(uint8_t data)
{
// P2 d7: PIT8253 write strobe
// P2 d5,d6: PIT8253 A0,A1
if (~m_musicBus & data & 0x80)
m_pit->write(data >> 5 & 3, m_musicData);
m_musicBus = data;
}
void carnival_state::carnivalb_audio(machine_config &config)
{
// already inherited carnivala_audio
config.device_remove("psg");
m_audiocpu->p1_out_cb().set(FUNC(carnival_state::carnivalb_music_port_1_w));
m_audiocpu->p2_out_cb().set(FUNC(carnival_state::carnivalb_music_port_2_w));
PIT8253(config, m_pit, 0);
m_pit->set_clk<0>(XTAL(3'579'545)/3);
m_pit->set_clk<1>(XTAL(3'579'545)/3);
m_pit->set_clk<2>(XTAL(3'579'545)/3);
m_pit->out_handler<0>().set(m_dac[0], FUNC(dac_bit_interface::write));
m_pit->out_handler<1>().set(m_dac[1], FUNC(dac_bit_interface::write));
m_pit->out_handler<2>().set(m_dac[2], FUNC(dac_bit_interface::write));
for (int i = 0; i < 3; i++)
{
DAC_1BIT(config, m_dac[i]).add_route(ALL_OUTPUTS, "mono", 0.15);
VOLTAGE_REGULATOR(config, m_vref[i]).add_route(0, m_dac[i], 1.0, DAC_VREF_POS_INPUT);
}
}